| /* | |
| * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package sun.awt; | |
| import java.awt.AWTError; | |
| import java.awt.GraphicsDevice; | |
| import java.lang.ref.WeakReference; | |
| import java.net.InetAddress; | |
| import java.net.NetworkInterface; | |
| import java.net.SocketException; | |
| import java.net.UnknownHostException; | |
| import java.util.ArrayList; | |
| import java.util.Enumeration; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.ListIterator; | |
| import java.util.Map; | |
| import sun.awt.X11.XToolkit; | |
| import sun.java2d.SunGraphicsEnvironment; | |
| import sun.java2d.xr.XRSurfaceData; | |
| /** | |
| * This is an implementation of a GraphicsEnvironment object for the | |
| * default local GraphicsEnvironment used by the Java Runtime Environment | |
| * for X11 environments. | |
| * | |
| * @see GraphicsDevice | |
| * @see java.awt.GraphicsConfiguration | |
| */ | |
| public final class X11GraphicsEnvironment extends SunGraphicsEnvironment { | |
| static { | |
| initStatic(); | |
| } | |
| @SuppressWarnings("restricted") | |
| private static void initStatic() { | |
| System.loadLibrary("awt"); | |
| /* | |
| * Note: The XToolkit object depends on the static initializer | |
| * of X11GraphicsEnvironment to initialize the connection to | |
| * the X11 server. | |
| */ | |
| if (!isHeadless()) { | |
| // first check the OGL system property | |
| boolean glxRequested = false; | |
| String prop = System.getProperty("sun.java2d.opengl"); | |
| if (prop != null) { | |
| if (prop.equals("true") || prop.equals("t")) { | |
| glxRequested = true; | |
| } else if (prop.equals("True") || prop.equals("T")) { | |
| glxRequested = true; | |
| glxVerbose = true; | |
| } | |
| } | |
| // Now check for XRender system property | |
| boolean xRenderRequested = true; | |
| boolean xRenderIgnoreLinuxVersion = false; | |
| String xProp = System.getProperty("sun.java2d.xrender"); | |
| if (xProp != null) { | |
| if (xProp.equals("false") || xProp.equals("f")) { | |
| xRenderRequested = false; | |
| } else if (xProp.equals("True") || xProp.equals("T")) { | |
| xRenderRequested = true; | |
| xRenderVerbose = true; | |
| } | |
| if (xProp.equalsIgnoreCase("t") || xProp.equalsIgnoreCase("true")) { | |
| xRenderIgnoreLinuxVersion = true; | |
| } | |
| } | |
| // initialize the X11 display connection | |
| initDisplay(glxRequested); | |
| // only attempt to initialize GLX if it was requested | |
| if (glxRequested) { | |
| glxAvailable = initGLX(); | |
| if (glxVerbose && !glxAvailable) { | |
| System.out.println( | |
| "Could not enable OpenGL " + | |
| "pipeline (GLX 1.3 not available)"); | |
| } | |
| } | |
| // only attempt to initialize Xrender if it was requested | |
| if (xRenderRequested) { | |
| xRenderAvailable = initXRender(xRenderVerbose, xRenderIgnoreLinuxVersion); | |
| if (xRenderVerbose && !xRenderAvailable) { | |
| System.out.println( | |
| "Could not enable XRender pipeline"); | |
| } | |
| } | |
| if (xRenderAvailable) { | |
| XRSurfaceData.initXRSurfaceData(); | |
| } | |
| } | |
| } | |
| private static boolean glxAvailable; | |
| private static boolean glxVerbose; | |
| private static native boolean initGLX(); | |
| public static boolean isGLXAvailable() { | |
| return glxAvailable; | |
| } | |
| public static boolean isGLXVerbose() { | |
| return glxVerbose; | |
| } | |
| private static boolean xRenderVerbose; | |
| private static boolean xRenderAvailable; | |
| private static native boolean initXRender(boolean verbose, boolean ignoreLinuxVersion); | |
| public static boolean isXRenderAvailable() { | |
| return xRenderAvailable; | |
| } | |
| public static boolean isXRenderVerbose() { | |
| return xRenderVerbose; | |
| } | |
| /** | |
| * Checks if Shared Memory extension can be used. | |
| * Returns: | |
| * -1 if server doesn't support MITShm | |
| * 1 if server supports it and it can be used | |
| * 0 otherwise | |
| */ | |
| private static native int checkShmExt(); | |
| private static native String getDisplayString(); | |
| private Boolean isDisplayLocal; | |
| /** Available X11 screens. */ | |
| private final Map<Integer, X11GraphicsDevice> devices = new HashMap<>(5); | |
| /** | |
| * The key in the {@link #devices} for the main screen. | |
| */ | |
| private int mainScreen; | |
| // list of invalidated graphics devices (those which were removed) | |
| private List<WeakReference<X11GraphicsDevice>> oldDevices = new ArrayList<>(); | |
| /** | |
| * This should only be called from the static initializer, so no need for | |
| * the synchronized keyword. | |
| */ | |
| private static native void initDisplay(boolean glxRequested); | |
| @Override | |
| protected native int getNumScreens(); | |
| private native int getDefaultScreenNum(); | |
| public X11GraphicsEnvironment() { | |
| if (isHeadless()) { | |
| return; | |
| } | |
| /* Populate the device table */ | |
| rebuildDevices(); | |
| } | |
| /** | |
| * Initialize the native list of devices. | |
| */ | |
| private static native void initNativeData(); | |
| /** | |
| * Updates the list of devices and notify listeners. | |
| */ | |
| public void rebuildDevices() { | |
| XToolkit.awtLock(); | |
| try { | |
| initNativeData(); | |
| initDevices(); | |
| } finally { | |
| XToolkit.awtUnlock(); | |
| } | |
| displayChanged(); | |
| } | |
| /** | |
| * (Re)create all X11GraphicsDevices, reuses a devices if it is possible. | |
| */ | |
| private synchronized void initDevices() { | |
| Map<Integer, X11GraphicsDevice> old = new HashMap<>(devices); | |
| devices.clear(); | |
| int numScreens = getNumScreens(); | |
| if (numScreens == 0) { | |
| throw new AWTError("no screen devices"); | |
| } | |
| int index = getDefaultScreenNum(); | |
| mainScreen = 0 < index && index < numScreens ? index : 0; | |
| for (int id = 0; id < numScreens; ++id) { | |
| devices.put(id, old.containsKey(id) ? old.remove(id) : | |
| new X11GraphicsDevice(id)); | |
| } | |
| // if a device was not reused it should be invalidated | |
| for (X11GraphicsDevice gd : old.values()) { | |
| oldDevices.add(new WeakReference<>(gd)); | |
| } | |
| // Need to notify old devices, in case the user hold the reference to it | |
| for (ListIterator<WeakReference<X11GraphicsDevice>> it = | |
| oldDevices.listIterator(); it.hasNext(); ) { | |
| X11GraphicsDevice gd = it.next().get(); | |
| if (gd != null) { | |
| gd.invalidate(devices.get(mainScreen)); | |
| gd.displayChanged(); | |
| } else { | |
| // no more references to this device, remove it | |
| it.remove(); | |
| } | |
| } | |
| } | |
| @Override | |
| public synchronized GraphicsDevice getDefaultScreenDevice() { | |
| return devices.get(mainScreen); | |
| } | |
| @Override | |
| public synchronized GraphicsDevice[] getScreenDevices() { | |
| return devices.values().toArray(new X11GraphicsDevice[0]); | |
| } | |
| public synchronized GraphicsDevice getScreenDevice(int screen) { | |
| return devices.get(screen); | |
| } | |
| @Override | |
| protected GraphicsDevice makeScreenDevice(int screennum) { | |
| throw new UnsupportedOperationException("This method is unused and" + | |
| "should not be called in this implementation"); | |
| } | |
| @Override | |
| public boolean isDisplayLocal() { | |
| if (isDisplayLocal == null) { | |
| SunToolkit.awtLock(); | |
| try { | |
| if (isDisplayLocal == null) { | |
| isDisplayLocal = Boolean.valueOf(_isDisplayLocal()); | |
| } | |
| } finally { | |
| SunToolkit.awtUnlock(); | |
| } | |
| } | |
| return isDisplayLocal.booleanValue(); | |
| } | |
| private static boolean _isDisplayLocal() { | |
| if (isHeadless()) { | |
| return true; | |
| } | |
| String isRemote = System.getProperty("sun.java2d.remote"); | |
| if (isRemote != null) { | |
| return isRemote.equals("false"); | |
| } | |
| int shm = checkShmExt(); | |
| if (shm != -1) { | |
| return (shm == 1); | |
| } | |
| // If XServer doesn't support ShMem extension, | |
| // try the other way | |
| String display = getDisplayString(); | |
| int ind = display.indexOf(':'); | |
| final String hostName = display.substring(0, ind); | |
| if (ind <= 0) { | |
| // ':0' case | |
| return true; | |
| } | |
| InetAddress[] remAddr = null; | |
| Enumeration<InetAddress> locals = null; | |
| Enumeration<NetworkInterface> interfaces = null; | |
| try { | |
| interfaces = NetworkInterface.getNetworkInterfaces(); | |
| remAddr = InetAddress.getAllByName(hostName); | |
| if (remAddr == null) { | |
| return false; | |
| } | |
| } catch (UnknownHostException e) { | |
| System.err.println("Unknown host: " + hostName); | |
| return false; | |
| } catch (SocketException e1) { | |
| System.err.println(e1.getMessage()); | |
| return false; | |
| } | |
| for (; interfaces.hasMoreElements();) { | |
| locals = interfaces.nextElement().getInetAddresses(); | |
| for (; locals.hasMoreElements();) { | |
| final InetAddress localAddr = locals.nextElement(); | |
| for (int i = 0; i < remAddr.length; i++) { | |
| if (localAddr.equals(remAddr[i])) { | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| /** | |
| * Returns face name for default font, or null if | |
| * no face names are used for CompositeFontDescriptors | |
| * for this platform. | |
| */ | |
| public String getDefaultFontFaceName() { | |
| return null; | |
| } | |
| private static native boolean pRunningXinerama(); | |
| public boolean runningXinerama() { | |
| return pRunningXinerama(); | |
| } | |
| /** | |
| * From the DisplayChangedListener interface; devices do not need | |
| * to react to this event. | |
| */ | |
| @Override | |
| public void paletteChanged() { | |
| } | |
| } |