1 /* 2 * Copyright (c) 2012, 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.AWTPermission; 29 import java.awt.DisplayMode; 30 import java.awt.GraphicsConfiguration; 31 import java.awt.GraphicsDevice; 32 import java.awt.Insets; 33 import java.awt.Rectangle; 34 import java.awt.Window; 35 import java.awt.geom.Rectangle2D; 36 import java.util.Objects; 37 38 import sun.java2d.SunGraphicsEnvironment; 39 import sun.java2d.macos.MacOSFlags; 40 import sun.java2d.metal.MTLGraphicsConfig; 41 import sun.java2d.opengl.CGLGraphicsConfig; 42 43 public final class CGraphicsDevice extends GraphicsDevice 44 implements DisplayChangedListener { 45 46 /** 47 * CoreGraphics display ID. This identifier can become non-valid at any time 48 * therefore methods, which is using this id should be ready to it. 49 */ 50 private volatile int displayID; 51 private volatile double xResolution; 52 private volatile double yResolution; 53 private volatile Rectangle bounds; 54 private volatile int scale; 55 56 // Array of all GraphicsConfig instances for this device 57 private final GraphicsConfiguration[] configs; 58 59 // Default config (temporarily hard coded) 60 private final int DEFAULT_CONFIG = 0; 61 62 private static AWTPermission fullScreenExclusivePermission; 63 64 // Save/restore DisplayMode for the Full Screen mode 65 private DisplayMode originalMode; 66 67 public CGraphicsDevice(final int displayID) { 68 this.displayID = displayID; 69 configs = new GraphicsConfiguration[] { 70 MacOSFlags.isMetalEnabled() ? 71 MTLGraphicsConfig.getConfig(this, displayID, 0) : 72 CGLGraphicsConfig.getConfig(this, displayID, 0) 73 }; 74 } 75 76 /** 77 * Return a list of all configurations. 78 */ 79 @Override 80 public GraphicsConfiguration[] getConfigurations() { 81 return configs.clone(); 82 } 83 84 /** 85 * Return the default configuration. 86 */ 87 @Override 88 public GraphicsConfiguration getDefaultConfiguration() { 89 return configs[DEFAULT_CONFIG]; 90 } 91 92 /** 93 * Return a human-readable screen description. 94 */ 95 @Override 96 public String getIDstring() { 97 return "Display " + displayID; 98 } 99 100 /** 101 * Returns the type of the graphics device. 102 * @see #TYPE_RASTER_SCREEN 103 * @see #TYPE_PRINTER 104 * @see #TYPE_IMAGE_BUFFER 105 */ 106 @Override 107 public int getType() { 108 return TYPE_RASTER_SCREEN; 109 } 110 111 public double getXResolution() { 112 return xResolution; 113 } 114 115 public double getYResolution() { 116 return yResolution; 117 } 118 119 Rectangle getBounds() { 120 return bounds.getBounds(); 121 } 122 123 public Insets getScreenInsets() { 124 // the insets are queried synchronously and are not cached 125 // since there are no Quartz or Cocoa means to receive notifications 126 // on insets changes (e.g. when the Dock is resized): 127 // the existing CGDisplayReconfigurationCallBack is not notified 128 // as well as the NSApplicationDidChangeScreenParametersNotification 129 // is fired on the Dock location changes only 130 return nativeGetScreenInsets(displayID); 131 } 132 133 public int getScaleFactor() { 134 return scale; 135 } 136 137 public void invalidate(final int defaultDisplayID) { 138 displayID = defaultDisplayID; 139 } 140 141 @Override 142 public void displayChanged() { 143 xResolution = nativeGetXResolution(displayID); 144 yResolution = nativeGetYResolution(displayID); 145 bounds = nativeGetBounds(displayID).getBounds(); //does integer rounding 146 initScaleFactor(); 147 //TODO configs/fullscreenWindow/modes? 148 } 149 150 @Override 151 public void paletteChanged() { 152 // devices do not need to react to this event. 153 } 154 155 /** 156 * Enters full-screen mode, or returns to windowed mode. 157 */ 158 @Override 159 public synchronized void setFullScreenWindow(Window w) { 160 Window old = getFullScreenWindow(); 161 if (w == old) { 162 return; 163 } 164 165 boolean fsSupported = isFullScreenSupported(); 166 167 if (fsSupported && old != null) { 168 // enter windowed mode and restore original display mode 169 exitFullScreenExclusive(old); 170 if (originalMode != null) { 171 setDisplayMode(originalMode); 172 originalMode = null; 173 } 174 } 175 176 super.setFullScreenWindow(w); 177 178 if (fsSupported && w != null) { 179 if (isDisplayChangeSupported()) { 180 originalMode = getDisplayMode(); 181 } 182 // enter fullscreen mode 183 enterFullScreenExclusive(w); 184 } 185 } 186 187 /** 188 * Returns true if this GraphicsDevice supports 189 * full-screen exclusive mode and false otherwise. 190 */ 191 @Override 192 public boolean isFullScreenSupported() { 193 return isFSExclusiveModeAllowed(); 194 } 195 196 private static boolean isFSExclusiveModeAllowed() { 197 SecurityManager security = System.getSecurityManager(); 198 if (security != null) { 199 if (fullScreenExclusivePermission == null) { 200 fullScreenExclusivePermission = 201 new AWTPermission("fullScreenExclusive"); 202 } 203 try { 204 security.checkPermission(fullScreenExclusivePermission); 205 } catch (SecurityException e) { 206 return false; 207 } 208 } 209 return true; 210 } 211 212 private static void enterFullScreenExclusive(Window w) { 213 FullScreenCapable peer = AWTAccessor.getComponentAccessor().getPeer(w); 214 if (peer != null) { 215 peer.enterFullScreenMode(); 216 } 217 } 218 219 private static void exitFullScreenExclusive(Window w) { 220 FullScreenCapable peer = AWTAccessor.getComponentAccessor().getPeer(w); 221 if (peer != null) { 222 peer.exitFullScreenMode(); 223 } 224 } 225 226 @Override 227 public boolean isDisplayChangeSupported() { 228 return true; 229 } 230 231 @Override 232 public void setDisplayMode(final DisplayMode dm) { 233 if (dm == null) { 234 throw new IllegalArgumentException("Invalid display mode"); 235 } 236 if (!Objects.equals(dm, getDisplayMode())) { 237 nativeSetDisplayMode(displayID, dm.getWidth(), dm.getHeight(), 238 dm.getBitDepth(), dm.getRefreshRate()); 239 if (isFullScreenSupported() && getFullScreenWindow() != null) { 240 getFullScreenWindow().setSize(dm.getWidth(), dm.getHeight()); 241 } 242 } 243 } 244 245 @Override 246 public DisplayMode getDisplayMode() { 247 return nativeGetDisplayMode(displayID); 248 } 249 250 @Override 251 public DisplayMode[] getDisplayModes() { 252 return nativeGetDisplayModes(displayID); 253 } 254 255 private void initScaleFactor() { 256 if (SunGraphicsEnvironment.isUIScaleEnabled()) { 257 double debugScale = SunGraphicsEnvironment.getDebugScale(); 258 scale = (int) (debugScale >= 1 259 ? Math.round(debugScale) 260 : nativeGetScaleFactor(displayID)); 261 } else { 262 scale = 1; 263 } 264 } 265 266 private static native double nativeGetScaleFactor(int displayID); 267 268 private static native void nativeSetDisplayMode(int displayID, int w, int h, int bpp, int refrate); 269 270 private static native DisplayMode nativeGetDisplayMode(int displayID); 271 272 private static native DisplayMode[] nativeGetDisplayModes(int displayID); 273 274 private static native double nativeGetXResolution(int displayID); 275 276 private static native double nativeGetYResolution(int displayID); 277 278 private static native Insets nativeGetScreenInsets(int displayID); 279 280 private static native String nativeGetMetalDeviceName(int displayID); 281 282 private static native Rectangle2D nativeGetBounds(int displayID); 283 }