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