1 /* 2 * Copyright (c) 1997, 2010, 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.GraphicsDevice; 29 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.awt.motif.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() { 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 return getScreenDevices()[getDefaultScreenNum()]; 209 } 210 211 public boolean isDisplayLocal() { 212 if (isDisplayLocal == null) { 213 SunToolkit.awtLock(); 214 try { 215 if (isDisplayLocal == null) { 216 isDisplayLocal = Boolean.valueOf(_isDisplayLocal()); 217 } 218 } finally { 219 SunToolkit.awtUnlock(); 220 } 221 } 222 return isDisplayLocal.booleanValue(); 223 } 224 225 private static boolean _isDisplayLocal() { 226 if (isHeadless()) { 227 return true; 228 } 229 230 String isRemote = (String)java.security.AccessController.doPrivileged( 231 new sun.security.action.GetPropertyAction("sun.java2d.remote")); 232 if (isRemote != null) { 233 return isRemote.equals("false"); 234 } 235 236 int shm = checkShmExt(); 237 if (shm != -1) { 238 return (shm == 1); 239 } 240 241 // If XServer doesn't support ShMem extension, 242 // try the other way 243 244 String display = getDisplayString(); 245 int ind = display.indexOf(':'); 246 final String hostName = display.substring(0, ind); 247 if (ind <= 0) { 248 // ':0' case 249 return true; 250 } 251 252 Boolean result = (Boolean)java.security.AccessController.doPrivileged( 253 new java.security.PrivilegedAction() { 254 public Object run() { 255 InetAddress remAddr[] = null; 256 Enumeration locals = null; 257 Enumeration interfaces = null; 258 try { 259 interfaces = NetworkInterface.getNetworkInterfaces(); 260 remAddr = InetAddress.getAllByName(hostName); 261 if (remAddr == null) { 262 return Boolean.FALSE; 263 } 264 } catch (UnknownHostException e) { 265 System.err.println("Unknown host: " + hostName); 266 return Boolean.FALSE; 267 } catch (SocketException e1) { 268 System.err.println(e1.getMessage()); 269 return Boolean.FALSE; 270 } 271 272 for (; interfaces.hasMoreElements();) { 273 locals = ((NetworkInterface)interfaces.nextElement()).getInetAddresses(); 274 for (; locals.hasMoreElements();) { 275 for (int i = 0; i < remAddr.length; i++) { 276 if (locals.nextElement().equals(remAddr[i])) { 277 return Boolean.TRUE; 278 } 279 } 280 } 281 } 282 return Boolean.FALSE; 283 }}); 284 return result.booleanValue(); 285 } 286 287 288 289 /** 290 * Returns face name for default font, or null if 291 * no face names are used for CompositeFontDescriptors 292 * for this platform. 293 */ 294 public String getDefaultFontFaceName() { 295 296 return null; 297 } 298 299 private static native boolean pRunningXinerama(); 300 private static native Point getXineramaCenterPoint(); 301 302 /** 303 * Override for Xinerama case: call new Solaris API for getting the correct 304 * centering point from the windowing system. 305 */ 306 public Point getCenterPoint() { 307 if (runningXinerama()) { 308 Point p = getXineramaCenterPoint(); 309 if (p != null) { 310 return p; 311 } 312 } 313 return super.getCenterPoint(); 314 } 315 316 /** 317 * Override for Xinerama case 318 */ 319 public Rectangle getMaximumWindowBounds() { 320 if (runningXinerama()) { 321 return getXineramaWindowBounds(); 322 } else { 323 return super.getMaximumWindowBounds(); 324 } 325 } 326 327 public boolean runningXinerama() { 328 if (xinerState == null) { 329 // pRunningXinerama() simply returns a global boolean variable, 330 // so there is no need to synchronize here 331 xinerState = Boolean.valueOf(pRunningXinerama()); 332 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 333 screenLog.finer("Running Xinerama: " + xinerState); 334 } 335 } 336 return xinerState.booleanValue(); 337 } 338 339 /** 340 * Return the bounds for a centered Window on a system running in Xinerama 341 * mode. 342 * 343 * Calculations are based on the assumption of a perfectly rectangular 344 * display area (display edges line up with one another, and displays 345 * have consistent width and/or height). 346 * 347 * The bounds to return depend on the arrangement of displays and on where 348 * Windows are to be centered. There are two common situations: 349 * 350 * 1) The center point lies at the center of the combined area of all the 351 * displays. In this case, the combined area of all displays is 352 * returned. 353 * 354 * 2) The center point lies at the center of a single display. In this case 355 * the user most likely wants centered Windows to be constrained to that 356 * single display. The boundaries of the one display are returned. 357 * 358 * It is possible for the center point to be at both the center of the 359 * entire display space AND at the center of a single monitor (a square of 360 * 9 monitors, for instance). In this case, the entire display area is 361 * returned. 362 * 363 * Because the center point is arbitrarily settable by the user, it could 364 * fit neither of the cases above. The fallback case is to simply return 365 * the combined area for all screens. 366 */ 367 protected Rectangle getXineramaWindowBounds() { 368 Point center = getCenterPoint(); 369 Rectangle unionRect, tempRect; 370 GraphicsDevice[] gds = getScreenDevices(); 371 Rectangle centerMonitorRect = null; 372 int i; 373 374 // if center point is at the center of all monitors 375 // return union of all bounds 376 // 377 // MM*MM MMM M 378 // M*M * 379 // MMM M 380 381 // if center point is at center of a single monitor (but not of all 382 // monitors) 383 // return bounds of single monitor 384 // 385 // MMM MM 386 // MM* *M 387 388 // else, center is in some strange spot (such as on the border between 389 // monitors), and we should just return the union of all monitors 390 // 391 // MM MMM 392 // MM MMM 393 394 unionRect = getUsableBounds(gds[0]); 395 396 for (i = 0; i < gds.length; i++) { 397 tempRect = getUsableBounds(gds[i]); 398 if (centerMonitorRect == null && 399 // add a pixel or two for fudge-factor 400 (tempRect.width / 2) + tempRect.x > center.x - 1 && 401 (tempRect.height / 2) + tempRect.y > center.y - 1 && 402 (tempRect.width / 2) + tempRect.x < center.x + 1 && 403 (tempRect.height / 2) + tempRect.y < center.y + 1) { 404 centerMonitorRect = tempRect; 405 } 406 unionRect = unionRect.union(tempRect); 407 } 408 409 // first: check for center of all monitors (video wall) 410 // add a pixel or two for fudge-factor 411 if ((unionRect.width / 2) + unionRect.x > center.x - 1 && 412 (unionRect.height / 2) + unionRect.y > center.y - 1 && 413 (unionRect.width / 2) + unionRect.x < center.x + 1 && 414 (unionRect.height / 2) + unionRect.y < center.y + 1) { 415 416 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 417 screenLog.finer("Video Wall: center point is at center of all displays."); 418 } 419 return unionRect; 420 } 421 422 // next, check if at center of one monitor 423 if (centerMonitorRect != null) { 424 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 425 screenLog.finer("Center point at center of a particular " + 426 "monitor, but not of the entire virtual display."); 427 } 428 return centerMonitorRect; 429 } 430 431 // otherwise, the center is at some weird spot: return unionRect 432 if (screenLog.isLoggable(PlatformLogger.Level.FINER)) { 433 screenLog.finer("Center point is somewhere strange - return union of all bounds."); 434 } 435 return unionRect; 436 } 437 438 /** 439 * From the DisplayChangedListener interface; devices do not need 440 * to react to this event. 441 */ 442 @Override 443 public void paletteChanged() { 444 } 445 }