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