1 /* 2 * Copyright (c) 1997, 2021, 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.GraphicsDevice; 30 import java.lang.ref.WeakReference; 31 import java.net.InetAddress; 32 import java.net.NetworkInterface; 33 import java.net.SocketException; 34 import java.net.UnknownHostException; 35 import java.util.ArrayList; 36 import java.util.Enumeration; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.ListIterator; 40 import java.util.Map; 41 42 import sun.awt.X11.XToolkit; 43 import sun.java2d.SunGraphicsEnvironment; 44 import sun.java2d.SurfaceManagerFactory; 45 import sun.java2d.UnixSurfaceManagerFactory; 46 import sun.java2d.xr.XRSurfaceData; 47 48 /** 49 * This is an implementation of a GraphicsEnvironment object for the 50 * default local GraphicsEnvironment used by the Java Runtime Environment 51 * for X11 environments. 52 * 53 * @see GraphicsDevice 54 * @see java.awt.GraphicsConfiguration 55 */ 56 @SuppressWarnings("removal") 57 public final class X11GraphicsEnvironment extends SunGraphicsEnvironment { 58 59 static { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Object>() { public Object run() { System.loadLibrary(R); if (!isHeadless()) { boolean glxRequested = false; String prop = System.getProperty(R); if (prop != null) { if (prop.equals(R) || prop.equals(R)) { glxRequested = true; } else if (prop.equals(R) || prop.equals(R)) { glxRequested = true; glxVerbose = true; } } boolean xRenderRequested = true; boolean xRenderIgnoreLinuxVersion = false; String xProp = System.getProperty(R); if (xProp != null) { if (xProp.equals(R) || xProp.equals(R)) { xRenderRequested = false; } else if (xProp.equals(R) || xProp.equals(R)) { xRenderRequested = true; xRenderVerbose = true; } if(xProp.equalsIgnoreCase(R) || xProp.equalsIgnoreCase(R)) { xRenderIgnoreLinuxVersion = true; } } initDisplay(glxRequested); if (glxRequested) { glxAvailable = initGLX(); if (glxVerbose && !glxAvailable) { System.out.println( R + R); } } if (xRenderRequested) { xRenderAvailable = initXRender(xRenderVerbose, xRenderIgnoreLinuxVersion); if (xRenderVerbose && !xRenderAvailable) { System.out.println( R); } } if (xRenderAvailable) { XRSurfaceData.initXRSurfaceData(); } } return null; } })60 java.security.AccessController.doPrivileged( 61 new java.security.PrivilegedAction<Object>() { 62 public Object run() { 63 System.loadLibrary("awt"); 64 65 /* 66 * Note: The MToolkit object depends on the static initializer 67 * of X11GraphicsEnvironment to initialize the connection to 68 * the X11 server. 69 */ 70 if (!isHeadless()) { 71 // first check the OGL system property 72 boolean glxRequested = false; 73 String prop = System.getProperty("sun.java2d.opengl"); 74 if (prop != null) { 75 if (prop.equals("true") || prop.equals("t")) { 76 glxRequested = true; 77 } else if (prop.equals("True") || prop.equals("T")) { 78 glxRequested = true; 79 glxVerbose = true; 80 } 81 } 82 83 // Now check for XRender system property 84 boolean xRenderRequested = true; 85 boolean xRenderIgnoreLinuxVersion = false; 86 String xProp = System.getProperty("sun.java2d.xrender"); 87 if (xProp != null) { 88 if (xProp.equals("false") || xProp.equals("f")) { 89 xRenderRequested = false; 90 } else if (xProp.equals("True") || xProp.equals("T")) { 91 xRenderRequested = true; 92 xRenderVerbose = true; 93 } 94 95 if(xProp.equalsIgnoreCase("t") || xProp.equalsIgnoreCase("true")) { 96 xRenderIgnoreLinuxVersion = true; 97 } 98 } 99 100 // initialize the X11 display connection 101 initDisplay(glxRequested); 102 103 // only attempt to initialize GLX if it was requested 104 if (glxRequested) { 105 glxAvailable = initGLX(); 106 if (glxVerbose && !glxAvailable) { 107 System.out.println( 108 "Could not enable OpenGL " + 109 "pipeline (GLX 1.3 not available)"); 110 } 111 } 112 113 // only attempt to initialize Xrender if it was requested 114 if (xRenderRequested) { 115 xRenderAvailable = initXRender(xRenderVerbose, xRenderIgnoreLinuxVersion); 116 if (xRenderVerbose && !xRenderAvailable) { 117 System.out.println( 118 "Could not enable XRender pipeline"); 119 } 120 } 121 122 if (xRenderAvailable) { 123 XRSurfaceData.initXRSurfaceData(); 124 } 125 } 126 127 return null; 128 } 129 }); 130 131 // Install the correct surface manager factory. SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory())132 SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory()); 133 134 } 135 136 137 private static boolean glxAvailable; 138 private static boolean glxVerbose; 139 initGLX()140 private static native boolean initGLX(); 141 isGLXAvailable()142 public static boolean isGLXAvailable() { 143 return glxAvailable; 144 } 145 isGLXVerbose()146 public static boolean isGLXVerbose() { 147 return glxVerbose; 148 } 149 150 private static boolean xRenderVerbose; 151 private static boolean xRenderAvailable; 152 initXRender(boolean verbose, boolean ignoreLinuxVersion)153 private static native boolean initXRender(boolean verbose, boolean ignoreLinuxVersion); isXRenderAvailable()154 public static boolean isXRenderAvailable() { 155 return xRenderAvailable; 156 } 157 isXRenderVerbose()158 public static boolean isXRenderVerbose() { 159 return xRenderVerbose; 160 } 161 162 /** 163 * Checks if Shared Memory extension can be used. 164 * Returns: 165 * -1 if server doesn't support MITShm 166 * 1 if server supports it and it can be used 167 * 0 otherwise 168 */ checkShmExt()169 private static native int checkShmExt(); 170 getDisplayString()171 private static native String getDisplayString(); 172 private Boolean isDisplayLocal; 173 174 /** Available X11 screens. */ 175 private final Map<Integer, X11GraphicsDevice> devices = new HashMap<>(5); 176 177 /** 178 * The key in the {@link #devices} for the main screen. 179 */ 180 private int mainScreen; 181 182 // list of invalidated graphics devices (those which were removed) 183 private List<WeakReference<X11GraphicsDevice>> oldDevices = new ArrayList<>(); 184 185 /** 186 * This should only be called from the static initializer, so no need for 187 * the synchronized keyword. 188 */ initDisplay(boolean glxRequested)189 private static native void initDisplay(boolean glxRequested); 190 getNumScreens()191 protected native int getNumScreens(); 192 getDefaultScreenNum()193 private native int getDefaultScreenNum(); 194 X11GraphicsEnvironment()195 public X11GraphicsEnvironment() { 196 if (isHeadless()) { 197 return; 198 } 199 200 /* Populate the device table */ 201 rebuildDevices(); 202 } 203 204 /** 205 * Initialize the native list of devices. 206 */ initNativeData()207 private static native void initNativeData(); 208 209 /** 210 * Updates the list of devices and notify listeners. 211 */ rebuildDevices()212 public void rebuildDevices() { 213 XToolkit.awtLock(); 214 try { 215 initNativeData(); 216 initDevices(); 217 } finally { 218 XToolkit.awtUnlock(); 219 } 220 displayChanged(); 221 } 222 223 /** 224 * (Re)create all X11GraphicsDevices, reuses a devices if it is possible. 225 */ initDevices()226 private synchronized void initDevices() { 227 Map<Integer, X11GraphicsDevice> old = new HashMap<>(devices); 228 devices.clear(); 229 230 int numScreens = getNumScreens(); 231 if (numScreens == 0) { 232 throw new AWTError("no screen devices"); 233 } 234 int index = getDefaultScreenNum(); 235 mainScreen = 0 < index && index < screens.length ? index : 0; 236 237 for (int id = 0; id < numScreens; ++id) { 238 devices.put(id, old.containsKey(id) ? old.remove(id) : 239 new X11GraphicsDevice(id)); 240 } 241 // if a device was not reused it should be invalidated 242 for (X11GraphicsDevice gd : old.values()) { 243 oldDevices.add(new WeakReference<>(gd)); 244 } 245 // Need to notify old devices, in case the user hold the reference to it 246 for (ListIterator<WeakReference<X11GraphicsDevice>> it = 247 oldDevices.listIterator(); it.hasNext(); ) { 248 X11GraphicsDevice gd = it.next().get(); 249 if (gd != null) { 250 gd.invalidate(devices.get(mainScreen)); 251 gd.displayChanged(); 252 } else { 253 // no more references to this device, remove it 254 it.remove(); 255 } 256 } 257 } 258 259 @Override 260 public synchronized GraphicsDevice getDefaultScreenDevice() { 261 return devices.get(mainScreen); 262 } 263 264 @Override 265 public synchronized GraphicsDevice[] getScreenDevices() { 266 return devices.values().toArray(new X11GraphicsDevice[0]); 267 } 268 269 public synchronized GraphicsDevice getScreenDevice(int screen) { 270 return devices.get(screen); 271 } 272 273 @Override 274 protected GraphicsDevice makeScreenDevice(int screennum) { 275 throw new UnsupportedOperationException("This method is unused and" + 276 "should not be called in this implementation"); 277 } 278 279 public boolean isDisplayLocal() { 280 if (isDisplayLocal == null) { 281 SunToolkit.awtLock(); 282 try { 283 if (isDisplayLocal == null) { 284 isDisplayLocal = Boolean.valueOf(_isDisplayLocal()); 285 } 286 } finally { 287 SunToolkit.awtUnlock(); 288 } 289 } 290 return isDisplayLocal.booleanValue(); 291 } 292 293 private static boolean _isDisplayLocal() { 294 if (isHeadless()) { 295 return true; 296 } 297 298 String isRemote = java.security.AccessController.doPrivileged( 299 new sun.security.action.GetPropertyAction("sun.java2d.remote")); 300 if (isRemote != null) { 301 return isRemote.equals("false"); 302 } 303 304 int shm = checkShmExt(); 305 if (shm != -1) { 306 return (shm == 1); 307 } 308 309 // If XServer doesn't support ShMem extension, 310 // try the other way 311 312 String display = getDisplayString(); 313 int ind = display.indexOf(':'); 314 final String hostName = display.substring(0, ind); 315 if (ind <= 0) { 316 // ':0' case 317 return true; 318 } 319 320 Boolean result = java.security.AccessController.doPrivileged( 321 new java.security.PrivilegedAction<Boolean>() { 322 public Boolean run() { 323 InetAddress[] remAddr = null; 324 Enumeration<InetAddress> locals = null; 325 Enumeration<NetworkInterface> interfaces = null; 326 try { 327 interfaces = NetworkInterface.getNetworkInterfaces(); 328 remAddr = InetAddress.getAllByName(hostName); 329 if (remAddr == null) { 330 return Boolean.FALSE; 331 } 332 } catch (UnknownHostException e) { 333 System.err.println("Unknown host: " + hostName); 334 return Boolean.FALSE; 335 } catch (SocketException e1) { 336 System.err.println(e1.getMessage()); 337 return Boolean.FALSE; 338 } 339 340 for (; interfaces.hasMoreElements();) { 341 locals = interfaces.nextElement().getInetAddresses(); 342 for (; locals.hasMoreElements();) { 343 final InetAddress localAddr = locals.nextElement(); 344 for (int i = 0; i < remAddr.length; i++) { 345 if (localAddr.equals(remAddr[i])) { 346 return Boolean.TRUE; 347 } 348 } 349 } 350 } 351 return Boolean.FALSE; 352 }}); 353 return result.booleanValue(); 354 } 355 356 357 358 /** 359 * Returns face name for default font, or null if 360 * no face names are used for CompositeFontDescriptors 361 * for this platform. 362 */ 363 public String getDefaultFontFaceName() { 364 365 return null; 366 } 367 368 private static native boolean pRunningXinerama(); 369 370 public boolean runningXinerama() { 371 return pRunningXinerama(); 372 } 373 374 /** 375 * From the DisplayChangedListener interface; devices do not need 376 * to react to this event. 377 */ 378 @Override 379 public void paletteChanged() { 380 } 381 } 382