1 /* 2 * Copyright (c) 1997, 2014, 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.awt.Point; 31 import java.awt.Rectangle; 32 import java.io.BufferedReader; 33 import java.io.File; 34 import java.io.FileReader; 35 import java.io.FileNotFoundException; 36 import java.io.InputStream; 37 import java.io.IOException; 38 import java.io.StreamTokenizer; 39 import java.net.InetAddress; 40 import java.net.NetworkInterface; 41 import java.net.SocketException; 42 import java.net.UnknownHostException; 43 44 import java.util.*; 45 46 import sun.font.MFontConfiguration; 47 import sun.font.FcFontConfiguration; 48 import sun.font.Font2D; 49 import sun.font.FontManager; 50 import sun.font.NativeFont; 51 import sun.java2d.SunGraphicsEnvironment; 52 import sun.java2d.SurfaceManagerFactory; 53 import sun.java2d.UnixSurfaceManagerFactory; 54 import sun.util.logging.PlatformLogger; 55 import sun.java2d.xr.XRSurfaceData; 56 57 /** 58 * This is an implementation of a GraphicsEnvironment object for the 59 * default local GraphicsEnvironment used by the Java Runtime Environment 60 * for X11 environments. 61 * 62 * @see GraphicsDevice 63 * @see GraphicsConfiguration 64 */ 65 public class X11GraphicsEnvironment 66 extends SunGraphicsEnvironment 67 { 68 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11GraphicsEnvironment"); 69 private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.screen.X11GraphicsEnvironment"); 70 71 private static Boolean xinerState; 72 73 static { 74 java.security.AccessController.doPrivileged( 75 new java.security.PrivilegedAction<Object>() { 76 public Object run() { 77 System.loadLibrary("awt"); 78 79 /* 80 * Note: The MToolkit object depends on the static initializer 81 * of X11GraphicsEnvironment to initialize the connection to 82 * the X11 server. 83 */ 84 if (!isHeadless()) { 85 // first check the OGL system property 86 boolean glxRequested = false; 87 String prop = System.getProperty("sun.java2d.opengl"); 88 if (prop != null) { 89 if (prop.equals("true") || prop.equals("t")) { 90 glxRequested = true; 91 } else if (prop.equals("True") || prop.equals("T")) { 92 glxRequested = true; 93 glxVerbose = true; 94 } 95 } 96 97 // Now check for XRender system property 98 boolean xRenderRequested = true; 99 boolean xRenderIgnoreLinuxVersion = false; 100 String xProp = System.getProperty("sun.java2d.xrender"); 101 if (xProp != null) { 102 if (xProp.equals("false") || xProp.equals("f")) { 103 xRenderRequested = false; 104 } else if (xProp.equals("True") || xProp.equals("T")) { 105 xRenderRequested = true; 106 xRenderVerbose = true; 107 } 108 109 if(xProp.equalsIgnoreCase("t") || xProp.equalsIgnoreCase("true")) { 110 xRenderIgnoreLinuxVersion = true; 111 } 112 } 113 114 // initialize the X11 display connection 115 initDisplay(glxRequested); 116 117 // only attempt to initialize GLX if it was requested 118 if (glxRequested) { 119 glxAvailable = initGLX(); 120 if (glxVerbose && !glxAvailable) { 121 System.out.println( 122 "Could not enable OpenGL " + 123 "pipeline (GLX 1.3 not available)"); 124 } 125 } 126 127 // only attempt to initialize Xrender if it was requested 128 if (xRenderRequested) { 129 xRenderAvailable = initXRender(xRenderVerbose, xRenderIgnoreLinuxVersion); 130 if (xRenderVerbose && !xRenderAvailable) { 131 System.out.println( 132 "Could not enable XRender pipeline"); 133 } 134 } 135 136 if (xRenderAvailable) { 137 XRSurfaceData.initXRSurfaceData(); 138 } 139 } 140 141 return null; 142 } 143 }); 144 145 // Install the correct surface manager factory. 146 SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory()); 147 148 } 149 150 151 private static boolean glxAvailable; 152 private static boolean glxVerbose; 153 154 private static native boolean initGLX(); 155 156 public static boolean isGLXAvailable() { 157 return glxAvailable; 158 } 159 160 public static boolean isGLXVerbose() { 161 return glxVerbose; 162 } 163 164 private static boolean xRenderVerbose; 165 private static boolean xRenderAvailable; 166 167 private static native boolean initXRender(boolean verbose, boolean ignoreLinuxVersion); 168 public static boolean isXRenderAvailable() { 169 return xRenderAvailable; 170 } 171 172 public static boolean isXRenderVerbose() { 173 return xRenderVerbose; 174 } 175 176 /** 177 * Checks if Shared Memory extension can be used. 178 * Returns: 179 * -1 if server doesn't support MITShm 180 * 1 if server supports it and it can be used 181 * 0 otherwise 182 */ 183 private static native int checkShmExt(); 184 185 private static native String getDisplayString(); 186 private Boolean isDisplayLocal; 187 188 /** 189 * This should only be called from the static initializer, so no need for 190 * the synchronized keyword. 191 */ 192 private static native void initDisplay(boolean glxRequested); 193 194 public X11GraphicsEnvironment() { 195 } 196 197 protected native int getNumScreens(); 198 199 protected GraphicsDevice makeScreenDevice(int screennum) { 200 return new X11GraphicsDevice(screennum); 201 } 202 203 protected native int getDefaultScreenNum(); 204 /** 205 * Returns the default screen graphics device. 206 */ 207 public GraphicsDevice getDefaultScreenDevice() { 208 GraphicsDevice[] screens = getScreenDevices(); 209 if (screens.length == 0) { 210 throw new AWTError("no screen devices"); 211 } 212 int index = getDefaultScreenNum(); 213 return screens[0 < index && index < screens.length ? index : 0]; 214 } 215 216 public boolean isDisplayLocal() { 217 if (isDisplayLocal == null) { 218 SunToolkit.awtLock(); 219 try { 220 if (isDisplayLocal == null) { 221 isDisplayLocal = Boolean.valueOf(_isDisplayLocal()); 222 } 223 } finally { 224 SunToolkit.awtUnlock(); 225 } 226 } 227 return isDisplayLocal.booleanValue(); 228 } 229 230 private static boolean _isDisplayLocal() { 231 if (isHeadless()) { 232 return true; 233 } 234 235 String isRemote = java.security.AccessController.doPrivileged( 236 new sun.security.action.GetPropertyAction("sun.java2d.remote")); 237 if (isRemote != null) { 238 return isRemote.equals("false"); 239 } 240 241 int shm = checkShmExt(); 242 if (shm != -1) { 243 return (shm == 1); 244 } 245 246 // If XServer doesn't support ShMem extension, 247 // try the other way 248 249 String display = getDisplayString(); 250 int ind = display.indexOf(':'); 251 final String hostName = display.substring(0, ind); 252 if (ind <= 0) { 253 // ':0' case 254 return true; 255 } 256 257 Boolean result = java.security.AccessController.doPrivileged( 258 new java.security.PrivilegedAction<Boolean>() { 259 public Boolean run() { 260 InetAddress remAddr[] = null; 261 Enumeration<InetAddress> locals = null; 262 Enumeration<NetworkInterface> interfaces = null; 263 try { 264 interfaces = NetworkInterface.getNetworkInterfaces(); 265 remAddr = InetAddress.getAllByName(hostName); 266 if (remAddr == null) { 267 return Boolean.FALSE; 268 } 269 } catch (UnknownHostException e) { 270 System.err.println("Unknown host: " + hostName); 271 return Boolean.FALSE; 272 } catch (SocketException e1) { 273 System.err.println(e1.getMessage()); 274 return Boolean.FALSE; 275 } 276 277 for (; interfaces.hasMoreElements();) { 278 locals = interfaces.nextElement().getInetAddresses(); 279 for (; locals.hasMoreElements();) { 280 final InetAddress localAddr = locals.nextElement(); 281 for (int i = 0; i < remAddr.length; i++) { 282 if (localAddr.equals(remAddr[i])) { 283 return Boolean.TRUE; 284 } 285 } 286 } 287 } 288 return Boolean.FALSE; 289 }}); 290 return result.booleanValue(); 291 } 292 293 294 295 /** 296 * Returns face name for default font, or null if 297 * no face names are used for CompositeFontDescriptors 298 * for this platform. 299 */ 300 public String getDefaultFontFaceName() { 301 302 return null; 303 } 304 305 private static native boolean pRunningXinerama(); 306 private static native Point getXineramaCenterPoint(); 307 308 /** 309 * Override for Xinerama case: call new Solaris API for getting the correct 310 * centering point from the windowing system. 311 */ 312 public Point getCenterPoint() { 313 if (runningXinerama()) { 314 Point p = getXineramaCenterPoint(); 315 if (p != null) { 316 return p; 317 } 318 } 319 return super.getCenterPoint(); 320 } 321 322 /** 323 * Override for Xinerama case 324 */ 325 public Rectangle getMaximumWindowBounds() { 326 if (runningXinerama()) { 327 return getXineramaWindowBounds(); 328 } else { 329 return super.getMaximumWindowBounds(); 330 } 331 } 332 333 public boolean runningXinerama() { 334 if (xinerState == null) { 335 // pRunningXinerama() simply returns a global boolean variable, 336 // so there is no need to synchronize here 337 xinerState = Boolean.valueOf(pRunningXinerama()); 338 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 339 screenLog.finer("Running Xinerama: " + xinerState); 340 } 341 } 342 return xinerState.booleanValue(); 343 } 344 345 /** 346 * Return the bounds for a centered Window on a system running in Xinerama 347 * mode. 348 * 349 * Calculations are based on the assumption of a perfectly rectangular 350 * display area (display edges line up with one another, and displays 351 * have consistent width and/or height). 352 * 353 * The bounds to return depend on the arrangement of displays and on where 354 * Windows are to be centered. There are two common situations: 355 * 356 * 1) The center point lies at the center of the combined area of all the 357 * displays. In this case, the combined area of all displays is 358 * returned. 359 * 360 * 2) The center point lies at the center of a single display. In this case 361 * the user most likely wants centered Windows to be constrained to that 362 * single display. The boundaries of the one display are returned. 363 * 364 * It is possible for the center point to be at both the center of the 365 * entire display space AND at the center of a single monitor (a square of 366 * 9 monitors, for instance). In this case, the entire display area is 367 * returned. 368 * 369 * Because the center point is arbitrarily settable by the user, it could 370 * fit neither of the cases above. The fallback case is to simply return 371 * the combined area for all screens. 372 */ 373 protected Rectangle getXineramaWindowBounds() { 374 Point center = getCenterPoint(); 375 Rectangle unionRect, tempRect; 376 GraphicsDevice[] gds = getScreenDevices(); 377 Rectangle centerMonitorRect = null; 378 int i; 379 380 // if center point is at the center of all monitors 381 // return union of all bounds 382 // 383 // MM*MM MMM M 384 // M*M * 385 // MMM M 386 387 // if center point is at center of a single monitor (but not of all 388 // monitors) 389 // return bounds of single monitor 390 // 391 // MMM MM 392 // MM* *M 393 394 // else, center is in some strange spot (such as on the border between 395 // monitors), and we should just return the union of all monitors 396 // 397 // MM MMM 398 // MM MMM 399 400 unionRect = getUsableBounds(gds[0]); 401 402 for (i = 0; i < gds.length; i++) { 403 tempRect = getUsableBounds(gds[i]); 404 if (centerMonitorRect == null && 405 // add a pixel or two for fudge-factor 406 (tempRect.width / 2) + tempRect.x > center.x - 1 && 407 (tempRect.height / 2) + tempRect.y > center.y - 1 && 408 (tempRect.width / 2) + tempRect.x < center.x + 1 && 409 (tempRect.height / 2) + tempRect.y < center.y + 1) { 410 centerMonitorRect = tempRect; 411 } 412 unionRect = unionRect.union(tempRect); 413 } 414 415 // first: check for center of all monitors (video wall) 416 // add a pixel or two for fudge-factor 417 if ((unionRect.width / 2) + unionRect.x > center.x - 1 && 418 (unionRect.height / 2) + unionRect.y > center.y - 1 && 419 (unionRect.width / 2) + unionRect.x < center.x + 1 && 420 (unionRect.height / 2) + unionRect.y < center.y + 1) { 421 422 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 423 screenLog.finer("Video Wall: center point is at center of all displays."); 424 } 425 return unionRect; 426 } 427 428 // next, check if at center of one monitor 429 if (centerMonitorRect != null) { 430 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 431 screenLog.finer("Center point at center of a particular " + 432 "monitor, but not of the entire virtual display."); 433 } 434 return centerMonitorRect; 435 } 436 437 // otherwise, the center is at some weird spot: return unionRect 438 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 439 screenLog.finer("Center point is somewhere strange - return union of all bounds."); 440 } 441 return unionRect; 442 } 443 444 /** 445 * From the DisplayChangedListener interface; devices do not need 446 * to react to this event. 447 */ 448 @Override 449 public void paletteChanged() { 450 } 451 }