dongzanxun2790 2018-10-24 08:15
浏览 143
已采纳

如何检测当前的Go进程是否在无头(非GUI)环境中运行?

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.

  • 写回答

3条回答 默认 最新

  • douhuan1497 2018-10-25 10:42
    关注

    In the perceived absence of a library/solution for this, I've created one myself. https://github.com/christianhujer/isheadless

    Example Usage:

    package main
    
    import (
        . "fmt"
        . "github.com/christianhujer/isheadless"
        . "os"
    )
    
    func main() {
        headless := IsHeadless()
        Fprintf(Stderr, "%s: info: headless: %v
    ", Args[0], headless)
        Exit(map[bool]int{true: 0, false: 1}[headless])
    }
    

    Example runs:

    $ ./isheadless ; echo $?
    ./isheadless: info: headless: false
    1
    $ DISPLAY= ./isheadless ; echo $?
    ./isheadless: info: headless: true
    0
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥50 adb连接不到手机是怎么回事?
  • ¥15 vs2022无法联网
  • ¥15 TCP的客户端和服务器的互联
  • ¥15 VB.NET操作免驱摄像头
  • ¥15 笔记本上移动热点开关状态查询
  • ¥85 类鸟群Boids——仿真鸟群避障的相关问题
  • ¥15 CFEDEM自带算例错误,如何解决?
  • ¥15 有没有会使用flac3d软件的家人
  • ¥20 360摄像头无法解绑使用,请教解绑当前账号绑定问题,
  • ¥15 docker实践项目