Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a safe, programmatic way to determine if it's safe to open a Swing window?

Tags:

java

swing

I have a java app that the user might invoke from the command line by running java -jar app.jar or from a desktop environment by double-clicking the .jar file.

I would like the app to be able to detect if it can safely launch a Swing GUI or if it has to use a command-line interface. If I just start calling Swing functions without checking for the availability of a window system, Java bails out with an InternalError.

For instance, if I unset DISPLAY and run the application, I get:

java.lang.InternalError: Can't connect to X11 window server using '' as the value of the DISPLAY variable.
    at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
    at sun.awt.X11GraphicsEnvironment.access$200(X11GraphicsEnvironment.java:62)
    at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:178)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.awt.X11GraphicsEnvironment.(X11GraphicsEnvironment.java:142)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:186)
    at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:82)
    at sun.awt.X11.XToolkit.(XToolkit.java:112)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:186)
    at java.awt.Toolkit$2.run(Toolkit.java:849)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:841)
        [etc]

I could just try...catch the InternalError and run the command-line interface in that case, but I'd heard that one shouldn't catch Errors because they might leave the JVM in an inconsistent state. (Please correct me if I'm wrong.)

Is there any way that I can check to see if I can safely open a Swing window without catching an InternalError? (I could just check if the DISPLAY environment variable is not empty, but a non-empty DISPLAY is no guarantee that the X server actually works. Nor would that approach work in non-X11 environments.)

like image 944
Joe Avatar asked Dec 01 '22 02:12

Joe


2 Answers

You can use GraphicsEnvironment.isHeadless()

like image 180
camickr Avatar answered Dec 05 '22 10:12

camickr


I could just try...catch the InternalError and run the command-line interface in that case, but I'd heard that one shouldn't catch Errors because they might leave the JVM in an inconsistent state. (Please correct me if I'm wrong.)

Your understanding is half right.

It is a bad idea to catch an Error and attempt to recover / continue running because the JVM could (already) be in a state from which recovery is not possible.

However, catching a specific error, printing an informative diagnostic to the console and immediately exiting the JVM is a pretty safe thing to do. (The System.out / err streams are pretty resilient to most things that cause an Error being thrown.)

In this particular case, there's probably nothing you could do to recover. So bailing out is the most sensible option anyway. (Calling isHeadless() before you attempt to start the GUI is a better idea though.)

like image 41
Stephen C Avatar answered Dec 05 '22 09:12

Stephen C