1 /*
   2  * Copyright (c) 1997, 2018, 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.net.InetAddress;
  31 import java.net.NetworkInterface;
  32 import java.net.SocketException;
  33 import java.net.UnknownHostException;
  34 import java.util.Enumeration;
  35 
  36 import sun.java2d.SunGraphicsEnvironment;
  37 import sun.java2d.SurfaceManagerFactory;
  38 import sun.java2d.UnixSurfaceManagerFactory;
  39 import sun.java2d.xr.XRSurfaceData;
  40 import sun.util.logging.PlatformLogger;
  41 
  42 /**
  43  * This is an implementation of a GraphicsEnvironment object for the
  44  * default local GraphicsEnvironment used by the Java Runtime Environment
  45  * for X11 environments.
  46  *
  47  * @see GraphicsDevice
  48  * @see java.awt.GraphicsConfiguration
  49  */
  50 public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
  51 
  52     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11GraphicsEnvironment");
  53     private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.screen.X11GraphicsEnvironment");
  54 
  55     private static Boolean xinerState;
  56 
  57     static {
  58         java.security.AccessController.doPrivileged(
  59                           new java.security.PrivilegedAction<Object>() {
  60             public Object run() {
  61                 System.loadLibrary("awt");
  62 
  63                 /*
  64                  * Note: The MToolkit object depends on the static initializer
  65                  * of X11GraphicsEnvironment to initialize the connection to
  66                  * the X11 server.
  67                  */
  68                 if (!isHeadless()) {
  69                     // first check the OGL system property
  70                     boolean glxRequested = false;
  71                     String prop = System.getProperty("sun.java2d.opengl");
  72                     if (prop != null) {
  73                         if (prop.equals("true") || prop.equals("t")) {
  74                             glxRequested = true;
  75                         } else if (prop.equals("True") || prop.equals("T")) {
  76                             glxRequested = true;
  77                             glxVerbose = true;
  78                         }
  79                     }
  80 
  81                     // Now check for XRender system property
  82                     boolean xRenderRequested = true;
  83                     boolean xRenderIgnoreLinuxVersion = false;
  84                     String xProp = System.getProperty("sun.java2d.xrender");
  85                         if (xProp != null) {
  86                         if (xProp.equals("false") || xProp.equals("f")) {
  87                             xRenderRequested = false;
  88                         } else if (xProp.equals("True") || xProp.equals("T")) {
  89                             xRenderRequested = true;
  90                             xRenderVerbose = true;
  91                         }
  92 
  93                         if(xProp.equalsIgnoreCase("t") || xProp.equalsIgnoreCase("true")) {
  94                             xRenderIgnoreLinuxVersion = true;
  95                         }
  96                     }
  97 
  98                     // initialize the X11 display connection
  99                     initDisplay(glxRequested);
 100 
 101                     // only attempt to initialize GLX if it was requested
 102                     if (glxRequested) {
 103                         glxAvailable = initGLX();
 104                         if (glxVerbose && !glxAvailable) {
 105                             System.out.println(
 106                                 "Could not enable OpenGL " +
 107                                 "pipeline (GLX 1.3 not available)");
 108                         }
 109                     }
 110 
 111                     // only attempt to initialize Xrender if it was requested
 112                     if (xRenderRequested) {
 113                         xRenderAvailable = initXRender(xRenderVerbose, xRenderIgnoreLinuxVersion);
 114                         if (xRenderVerbose && !xRenderAvailable) {
 115                             System.out.println(
 116                                          "Could not enable XRender pipeline");
 117                         }
 118                     }
 119 
 120                     if (xRenderAvailable) {
 121                         XRSurfaceData.initXRSurfaceData();
 122                     }
 123                 }
 124 
 125                 return null;
 126             }
 127          });
 128 
 129         // Install the correct surface manager factory.
 130         SurfaceManagerFactory.setInstance(new UnixSurfaceManagerFactory());
 131 
 132     }
 133 
 134 
 135     private static boolean glxAvailable;
 136     private static boolean glxVerbose;
 137 
 138     private static native boolean initGLX();
 139 
 140     public static boolean isGLXAvailable() {
 141         return glxAvailable;
 142     }
 143 
 144     public static boolean isGLXVerbose() {
 145         return glxVerbose;
 146     }
 147 
 148     private static boolean xRenderVerbose;
 149     private static boolean xRenderAvailable;
 150 
 151     private static native boolean initXRender(boolean verbose, boolean ignoreLinuxVersion);
 152     public static boolean isXRenderAvailable() {
 153         return xRenderAvailable;
 154     }
 155 
 156     public static boolean isXRenderVerbose() {
 157         return xRenderVerbose;
 158     }
 159 
 160     /**
 161      * Checks if Shared Memory extension can be used.
 162      * Returns:
 163      *   -1 if server doesn't support MITShm
 164      *    1 if server supports it and it can be used
 165      *    0 otherwise
 166      */
 167     private static native int checkShmExt();
 168 
 169     private static  native String getDisplayString();
 170     private Boolean isDisplayLocal;
 171 
 172     /**
 173      * This should only be called from the static initializer, so no need for
 174      * the synchronized keyword.
 175      */
 176     private static native void initDisplay(boolean glxRequested);
 177 
 178     public X11GraphicsEnvironment() {
 179     }
 180 
 181     protected native int getNumScreens();
 182 
 183     protected GraphicsDevice makeScreenDevice(int screennum) {
 184         return new X11GraphicsDevice(screennum);
 185     }
 186 
 187     private native int getDefaultScreenNum();
 188     /**
 189      * Returns the default screen graphics device.
 190      */
 191     public GraphicsDevice getDefaultScreenDevice() {
 192         GraphicsDevice[] screens = getScreenDevices();
 193         if (screens.length == 0) {
 194             throw new AWTError("no screen devices");
 195         }
 196         int index = getDefaultScreenNum();
 197         return screens[0 < index && index < screens.length ? index : 0];
 198     }
 199 
 200     public boolean isDisplayLocal() {
 201         if (isDisplayLocal == null) {
 202             SunToolkit.awtLock();
 203             try {
 204                 if (isDisplayLocal == null) {
 205                     isDisplayLocal = Boolean.valueOf(_isDisplayLocal());
 206                 }
 207             } finally {
 208                 SunToolkit.awtUnlock();
 209             }
 210         }
 211         return isDisplayLocal.booleanValue();
 212     }
 213 
 214     private static boolean _isDisplayLocal() {
 215         if (isHeadless()) {
 216             return true;
 217         }
 218 
 219         String isRemote = java.security.AccessController.doPrivileged(
 220             new sun.security.action.GetPropertyAction("sun.java2d.remote"));
 221         if (isRemote != null) {
 222             return isRemote.equals("false");
 223         }
 224 
 225         int shm = checkShmExt();
 226         if (shm != -1) {
 227             return (shm == 1);
 228         }
 229 
 230         // If XServer doesn't support ShMem extension,
 231         // try the other way
 232 
 233         String display = getDisplayString();
 234         int ind = display.indexOf(':');
 235         final String hostName = display.substring(0, ind);
 236         if (ind <= 0) {
 237             // ':0' case
 238             return true;
 239         }
 240 
 241         Boolean result = java.security.AccessController.doPrivileged(
 242             new java.security.PrivilegedAction<Boolean>() {
 243             public Boolean run() {
 244                 InetAddress[] remAddr = null;
 245                 Enumeration<InetAddress> locals = null;
 246                 Enumeration<NetworkInterface> interfaces = null;
 247                 try {
 248                     interfaces = NetworkInterface.getNetworkInterfaces();
 249                     remAddr = InetAddress.getAllByName(hostName);
 250                     if (remAddr == null) {
 251                         return Boolean.FALSE;
 252                     }
 253                 } catch (UnknownHostException e) {
 254                     System.err.println("Unknown host: " + hostName);
 255                     return Boolean.FALSE;
 256                 } catch (SocketException e1) {
 257                     System.err.println(e1.getMessage());
 258                     return Boolean.FALSE;
 259                 }
 260 
 261                 for (; interfaces.hasMoreElements();) {
 262                     locals = interfaces.nextElement().getInetAddresses();
 263                     for (; locals.hasMoreElements();) {
 264                         final InetAddress localAddr = locals.nextElement();
 265                         for (int i = 0; i < remAddr.length; i++) {
 266                             if (localAddr.equals(remAddr[i])) {
 267                                 return Boolean.TRUE;
 268                             }
 269                         }
 270                     }
 271                 }
 272                 return Boolean.FALSE;
 273             }});
 274         return result.booleanValue();
 275     }
 276 
 277 
 278 
 279     /**
 280      * Returns face name for default font, or null if
 281      * no face names are used for CompositeFontDescriptors
 282      * for this platform.
 283      */
 284     public String getDefaultFontFaceName() {
 285 
 286         return null;
 287     }
 288 
 289     private static native boolean pRunningXinerama();
 290 
 291     public boolean runningXinerama() {
 292         if (xinerState == null) {
 293             // pRunningXinerama() simply returns a global boolean variable,
 294             // so there is no need to synchronize here
 295             xinerState = Boolean.valueOf(pRunningXinerama());
 296             if (screenLog.isLoggable(PlatformLogger.Level.FINER)) {
 297                 screenLog.finer("Running Xinerama: " + xinerState);
 298             }
 299         }
 300         return xinerState.booleanValue();
 301     }
 302 
 303     /**
 304      * From the DisplayChangedListener interface; devices do not need
 305      * to react to this event.
 306      */
 307     @Override
 308     public void paletteChanged() {
 309     }
 310 }