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条)

报告相同问题?

悬赏问题

  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 关于#python#的问题:自动化测试