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