View Javadoc
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  
27  package java.awt;
28  
29  import java.awt.image.BufferedImage;
30  import java.security.AccessController;
31  import java.util.Locale;
32  
33  import sun.font.FontManager;
34  import sun.font.FontManagerFactory;
35  import sun.java2d.HeadlessGraphicsEnvironment;
36  import sun.java2d.SunGraphicsEnvironment;
37  import sun.security.action.GetPropertyAction;
38  
39  /**
40   *
41   * The <code>GraphicsEnvironment</code> class describes the collection
42   * of {@link GraphicsDevice} objects and {@link java.awt.Font} objects
43   * available to a Java(tm) application on a particular platform.
44   * The resources in this <code>GraphicsEnvironment</code> might be local
45   * or on a remote machine.  <code>GraphicsDevice</code> objects can be
46   * screens, printers or image buffers and are the destination of
47   * {@link Graphics2D} drawing methods.  Each <code>GraphicsDevice</code>
48   * has a number of {@link GraphicsConfiguration} objects associated with
49   * it.  These objects specify the different configurations in which the
50   * <code>GraphicsDevice</code> can be used.
51   * @see GraphicsDevice
52   * @see GraphicsConfiguration
53   */
54  
55  public abstract class GraphicsEnvironment {
56      private static GraphicsEnvironment localEnv;
57  
58      /**
59       * The headless state of the Toolkit and GraphicsEnvironment
60       */
61      private static Boolean headless;
62  
63      /**
64       * The headless state assumed by default
65       */
66      private static Boolean defaultHeadless;
67  
68      /**
69       * This is an abstract class and cannot be instantiated directly.
70       * Instances must be obtained from a suitable factory or query method.
71       */
72      protected GraphicsEnvironment() {
73      }
74  
75      /**
76       * Returns the local <code>GraphicsEnvironment</code>.
77       * @return the local <code>GraphicsEnvironment</code>
78       */
79      public static synchronized GraphicsEnvironment getLocalGraphicsEnvironment() {
80          if (localEnv == null) {
81              localEnv = createGE();
82          }
83  
84          return localEnv;
85      }
86  
87      /**
88       * Creates and returns the GraphicsEnvironment, according to the
89       * system property 'java.awt.graphicsenv'.
90       *
91       * @return the graphics environment
92       */
93      private static GraphicsEnvironment createGE() {
94          GraphicsEnvironment ge;
95          String nm = AccessController.doPrivileged(new GetPropertyAction("java.awt.graphicsenv", null));
96          try {
97  //          long t0 = System.currentTimeMillis();
98              Class<GraphicsEnvironment> geCls;
99              try {
100                 // First we try if the bootclassloader finds the requested
101                 // class. This way we can avoid to run in a privileged block.
102                 geCls = (Class<GraphicsEnvironment>)Class.forName(nm);
103             } catch (ClassNotFoundException ex) {
104                 // If the bootclassloader fails, we try again with the
105                 // application classloader.
106                 ClassLoader cl = ClassLoader.getSystemClassLoader();
107                 geCls = (Class<GraphicsEnvironment>)Class.forName(nm, true, cl);
108             }
109             ge = geCls.newInstance();
110 //          long t1 = System.currentTimeMillis();
111 //          System.out.println("GE creation took " + (t1-t0)+ "ms.");
112             if (isHeadless()) {
113                 ge = new HeadlessGraphicsEnvironment(ge);
114             }
115         } catch (ClassNotFoundException e) {
116             throw new Error("Could not find class: "+nm);
117         } catch (InstantiationException e) {
118             throw new Error("Could not instantiate Graphics Environment: "
119                             + nm);
120         } catch (IllegalAccessException e) {
121             throw new Error ("Could not access Graphics Environment: "
122                              + nm);
123         }
124         return ge;
125     }
126 
127     /**
128      * Tests whether or not a display, keyboard, and mouse can be
129      * supported in this environment.  If this method returns true,
130      * a HeadlessException is thrown from areas of the Toolkit
131      * and GraphicsEnvironment that are dependent on a display,
132      * keyboard, or mouse.
133      * @return <code>true</code> if this environment cannot support
134      * a display, keyboard, and mouse; <code>false</code>
135      * otherwise
136      * @see java.awt.HeadlessException
137      * @since 1.4
138      */
139     public static boolean isHeadless() {
140         return getHeadlessProperty();
141     }
142 
143     /**
144      * @return warning message if headless state is assumed by default;
145      * null otherwise
146      * @since 1.5
147      */
148     static String getHeadlessMessage() {
149         if (headless == null) {
150             getHeadlessProperty(); // initialize the values
151         }
152         return defaultHeadless != Boolean.TRUE ? null :
153             "\nNo X11 DISPLAY variable was set, " +
154             "but this program performed an operation which requires it.";
155     }
156 
157     /**
158      * @return the value of the property "java.awt.headless"
159      * @since 1.4
160      */
161     private static boolean getHeadlessProperty() {
162         if (headless == null) {
163             java.security.AccessController.doPrivileged(
164             new java.security.PrivilegedAction<Object>() {
165                 public Object run() {
166                     String nm = System.getProperty("java.awt.headless");
167 
168                     if (nm == null) {
169                         /* No need to ask for DISPLAY when run in a browser */
170                         if (System.getProperty("javaplugin.version") != null) {
171                             headless = defaultHeadless = Boolean.FALSE;
172                         } else {
173                             String osName = System.getProperty("os.name");
174                             if (osName.contains("OS X") && "sun.awt.HToolkit".equals(
175                                     System.getProperty("awt.toolkit")))
176                             {
177                                 headless = defaultHeadless = Boolean.TRUE;
178                             } else {
179                                 headless = defaultHeadless =
180                                     Boolean.valueOf(("Linux".equals(osName) ||
181                                                      "SunOS".equals(osName) ||
182                                                      "FreeBSD".equals(osName) ||
183                                                      "NetBSD".equals(osName) ||
184                                                      "OpenBSD".equals(osName)) &&
185                                                      (System.getenv("DISPLAY") == null));
186                             }
187                         }
188                     } else if (nm.equals("true")) {
189                         headless = Boolean.TRUE;
190                     } else {
191                         headless = Boolean.FALSE;
192                     }
193                     return null;
194                 }
195                 }
196             );
197         }
198         return headless.booleanValue();
199     }
200 
201     /**
202      * Check for headless state and throw HeadlessException if headless
203      * @since 1.4
204      */
205     static void checkHeadless() throws HeadlessException {
206         if (isHeadless()) {
207             throw new HeadlessException();
208         }
209     }
210 
211     /**
212      * Returns whether or not a display, keyboard, and mouse can be
213      * supported in this graphics environment.  If this returns true,
214      * <code>HeadlessException</code> will be thrown from areas of the
215      * graphics environment that are dependent on a display, keyboard, or
216      * mouse.
217      * @return <code>true</code> if a display, keyboard, and mouse
218      * can be supported in this environment; <code>false</code>
219      * otherwise
220      * @see java.awt.HeadlessException
221      * @see #isHeadless
222      * @since 1.4
223      */
224     public boolean isHeadlessInstance() {
225         // By default (local graphics environment), simply check the
226         // headless property.
227         return getHeadlessProperty();
228     }
229 
230     /**
231      * Returns an array of all of the screen <code>GraphicsDevice</code>
232      * objects.
233      * @return an array containing all the <code>GraphicsDevice</code>
234      * objects that represent screen devices
235      * @exception HeadlessException if isHeadless() returns true
236      * @see #isHeadless()
237      */
238     public abstract GraphicsDevice[] getScreenDevices()
239         throws HeadlessException;
240 
241     /**
242      * Returns the default screen <code>GraphicsDevice</code>.
243      * @return the <code>GraphicsDevice</code> that represents the
244      * default screen device
245      * @exception HeadlessException if isHeadless() returns true
246      * @see #isHeadless()
247      */
248     public abstract GraphicsDevice getDefaultScreenDevice()
249         throws HeadlessException;
250 
251     /**
252      * Returns a <code>Graphics2D</code> object for rendering into the
253      * specified {@link BufferedImage}.
254      * @param img the specified <code>BufferedImage</code>
255      * @return a <code>Graphics2D</code> to be used for rendering into
256      * the specified <code>BufferedImage</code>
257      * @throws NullPointerException if <code>img</code> is null
258      */
259     public abstract Graphics2D createGraphics(BufferedImage img);
260 
261     /**
262      * Returns an array containing a one-point size instance of all fonts
263      * available in this <code>GraphicsEnvironment</code>.  Typical usage
264      * would be to allow a user to select a particular font.  Then, the
265      * application can size the font and set various font attributes by
266      * calling the <code>deriveFont</code> method on the chosen instance.
267      * <p>
268      * This method provides for the application the most precise control
269      * over which <code>Font</code> instance is used to render text.
270      * If a font in this <code>GraphicsEnvironment</code> has multiple
271      * programmable variations, only one
272      * instance of that <code>Font</code> is returned in the array, and
273      * other variations must be derived by the application.
274      * <p>
275      * If a font in this environment has multiple programmable variations,
276      * such as Multiple-Master fonts, only one instance of that font is
277      * returned in the <code>Font</code> array.  The other variations
278      * must be derived by the application.
279      *
280      * @return an array of <code>Font</code> objects
281      * @see #getAvailableFontFamilyNames
282      * @see java.awt.Font
283      * @see java.awt.Font#deriveFont
284      * @see java.awt.Font#getFontName
285      * @since 1.2
286      */
287     public abstract Font[] getAllFonts();
288 
289     /**
290      * Returns an array containing the names of all font families in this
291      * <code>GraphicsEnvironment</code> localized for the default locale,
292      * as returned by <code>Locale.getDefault()</code>.
293      * <p>
294      * Typical usage would be for presentation to a user for selection of
295      * a particular family name. An application can then specify this name
296      * when creating a font, in conjunction with a style, such as bold or
297      * italic, giving the font system flexibility in choosing its own best
298      * match among multiple fonts in the same font family.
299      *
300      * @return an array of <code>String</code> containing font family names
301      * localized for the default locale, or a suitable alternative
302      * name if no name exists for this locale.
303      * @see #getAllFonts
304      * @see java.awt.Font
305      * @see java.awt.Font#getFamily
306      * @since 1.2
307      */
308     public abstract String[] getAvailableFontFamilyNames();
309 
310     /**
311      * Returns an array containing the names of all font families in this
312      * <code>GraphicsEnvironment</code> localized for the specified locale.
313      * <p>
314      * Typical usage would be for presentation to a user for selection of
315      * a particular family name. An application can then specify this name
316      * when creating a font, in conjunction with a style, such as bold or
317      * italic, giving the font system flexibility in choosing its own best
318      * match among multiple fonts in the same font family.
319      *
320      * @param l a {@link Locale} object that represents a
321      * particular geographical, political, or cultural region.
322      * Specifying <code>null</code> is equivalent to
323      * specifying <code>Locale.getDefault()</code>.
324      * @return an array of <code>String</code> containing font family names
325      * localized for the specified <code>Locale</code>, or a
326      * suitable alternative name if no name exists for the specified locale.
327      * @see #getAllFonts
328      * @see java.awt.Font
329      * @see java.awt.Font#getFamily
330      * @since 1.2
331      */
332     public abstract String[] getAvailableFontFamilyNames(Locale l);
333 
334     /**
335      * Registers a <i>created</i> <code>Font</code>in this
336      * <code>GraphicsEnvironment</code>.
337      * A created font is one that was returned from calling
338      * {@link Font#createFont}, or derived from a created font by
339      * calling {@link Font#deriveFont}.
340      * After calling this method for such a font, it is available to
341      * be used in constructing new <code>Font</code>s by name or family name,
342      * and is enumerated by {@link #getAvailableFontFamilyNames} and
343      * {@link #getAllFonts} within the execution context of this
344      * application or applet. This means applets cannot register fonts in
345      * a way that they are visible to other applets.
346      * <p>
347      * Reasons that this method might not register the font and therefore
348      * return <code>false</code> are:
349      * <ul>
350      * <li>The font is not a <i>created</i> <code>Font</code>.
351      * <li>The font conflicts with a non-created <code>Font</code> already
352      * in this <code>GraphicsEnvironment</code>. For example if the name
353      * is that of a system font, or a logical font as described in the
354      * documentation of the {@link Font} class. It is implementation dependent
355      * whether a font may also conflict if it has the same family name
356      * as a system font.
357      * <p>Notice that an application can supersede the registration
358      * of an earlier created font with a new one.
359      * </ul>
360      * @return true if the <code>font</code> is successfully
361      * registered in this <code>GraphicsEnvironment</code>.
362      * @throws NullPointerException if <code>font</code> is null
363      * @since 1.6
364      */
365     public boolean registerFont(Font font) {
366         if (font == null) {
367             throw new NullPointerException("font cannot be null.");
368         }
369         FontManager fm = FontManagerFactory.getInstance();
370         return fm.registerFont(font);
371     }
372 
373     /**
374      * Indicates a preference for locale-specific fonts in the mapping of
375      * logical fonts to physical fonts. Calling this method indicates that font
376      * rendering should primarily use fonts specific to the primary writing
377      * system (the one indicated by the default encoding and the initial
378      * default locale). For example, if the primary writing system is
379      * Japanese, then characters should be rendered using a Japanese font
380      * if possible, and other fonts should only be used for characters for
381      * which the Japanese font doesn't have glyphs.
382      * <p>
383      * The actual change in font rendering behavior resulting from a call
384      * to this method is implementation dependent; it may have no effect at
385      * all, or the requested behavior may already match the default behavior.
386      * The behavior may differ between font rendering in lightweight
387      * and peered components.  Since calling this method requests a
388      * different font, clients should expect different metrics, and may need
389      * to recalculate window sizes and layout. Therefore this method should
390      * be called before user interface initialisation.
391      * @since 1.5
392      */
393     public void preferLocaleFonts() {
394         FontManager fm = FontManagerFactory.getInstance();
395         fm.preferLocaleFonts();
396     }
397 
398     /**
399      * Indicates a preference for proportional over non-proportional (e.g.
400      * dual-spaced CJK fonts) fonts in the mapping of logical fonts to
401      * physical fonts. If the default mapping contains fonts for which
402      * proportional and non-proportional variants exist, then calling
403      * this method indicates the mapping should use a proportional variant.
404      * <p>
405      * The actual change in font rendering behavior resulting from a call to
406      * this method is implementation dependent; it may have no effect at all.
407      * The behavior may differ between font rendering in lightweight and
408      * peered components. Since calling this method requests a
409      * different font, clients should expect different metrics, and may need
410      * to recalculate window sizes and layout. Therefore this method should
411      * be called before user interface initialisation.
412      * @since 1.5
413      */
414     public void preferProportionalFonts() {
415         FontManager fm = FontManagerFactory.getInstance();
416         fm.preferProportionalFonts();
417     }
418 
419     /**
420      * Returns the Point where Windows should be centered.
421      * It is recommended that centered Windows be checked to ensure they fit
422      * within the available display area using getMaximumWindowBounds().
423      * @return the point where Windows should be centered
424      *
425      * @exception HeadlessException if isHeadless() returns true
426      * @see #getMaximumWindowBounds
427      * @since 1.4
428      */
429     public Point getCenterPoint() throws HeadlessException {
430     // Default implementation: return the center of the usable bounds of the
431     // default screen device.
432         Rectangle usableBounds =
433          SunGraphicsEnvironment.getUsableBounds(getDefaultScreenDevice());
434         return new Point((usableBounds.width / 2) + usableBounds.x,
435                          (usableBounds.height / 2) + usableBounds.y);
436     }
437 
438     /**
439      * Returns the maximum bounds for centered Windows.
440      * These bounds account for objects in the native windowing system such as
441      * task bars and menu bars.  The returned bounds will reside on a single
442      * display with one exception: on multi-screen systems where Windows should
443      * be centered across all displays, this method returns the bounds of the
444      * entire display area.
445      * <p>
446      * To get the usable bounds of a single display, use
447      * <code>GraphicsConfiguration.getBounds()</code> and
448      * <code>Toolkit.getScreenInsets()</code>.
449      * @return  the maximum bounds for centered Windows
450      *
451      * @exception HeadlessException if isHeadless() returns true
452      * @see #getCenterPoint
453      * @see GraphicsConfiguration#getBounds
454      * @see Toolkit#getScreenInsets
455      * @since 1.4
456      */
457     public Rectangle getMaximumWindowBounds() throws HeadlessException {
458     // Default implementation: return the usable bounds of the default screen
459     // device.  This is correct for Microsoft Windows and non-Xinerama X11.
460         return SunGraphicsEnvironment.getUsableBounds(getDefaultScreenDevice());
461     }
462 }