I have a Go program which wants to install a trayicon. In case the process is headless, that is, it will not be able to create a graphical user interface, the Go program still makes sense and shall run, but obviously it shall not install the trayicon.
What is the way in Go how to detect whether the current Go process is headless?
Currently, I use the following code:
func isHeadless() bool {
_, display := os.LookupEnv("DISPLAY")
return !(runtime.GOOS == "windows" || display)
}
This code works just fine on a "normal" Windows, Linux, or Mac OS X, and I bet it will also run just fine on FreeBSD, NetBSD, Dragonfly and many others.
Still, that code obviously has a lot of problems:
- It assumes that Windows is never headless (wrong, what if the process was started without a user logged in, and also, there's Windows 10 IoT Core which can be configured to headless https://docs.microsoft.com/en-us/windows/iot-core/learn-about-hardware/headlessmode)
- It doesn't support Android (of which there also is a headless version for IoT).
- It assumes that everything non-Windows has an X-Server and thus a DISPLAY environment variable (wrong, for example, Android)
So, what is the correct way in Go to detect whether the current process is headless / running in a headless environment?
I'm not looking for workarounds, like adding a --headless
command line switch to my program. Because, I already have that anyway for users who have heads but want the program to behave as if it were headless.
In some other programming environments, such capabilities exist. For example, Java has java.awt.GraphicsEnvironment.isHeadless()
, and I'm looking for a similar capability in Go.
Some people have suggested to simply try creating the UI, and catch the error. This does not work, at least not with the library that I use. I use github.com/getlantern/systray
. When systray.Run()
cannot create the UI, the process dies. My code to setup the system tray looks like this:
func setupSystray() { // called from main()
go func() {
systray.Run(onReady, nil)
}()
}
func onReady() {
systray.SetTitle("foo")
// ...
}
When I run this code on Linux with DISPLAY
unset, the output is as following:
$ ./myapp-linux-amd64
Unable to init server: Could not connect: Connection refused
(myapp-linux-amd64:5783): Gtk-WARNING **: 19:42:37.914: cannot open display:
$ echo $?
1
It could be argued that this is a flaw in the library (and I have created a ticket on the library https://github.com/getlantern/systray/issues/71), but nonetheless some other APIs and environments provide a function isHeadless()
, and I'm looking for an equivalent in Golang.