//go:build linux package main import ( "errors" "fmt" "os" "sync" ) type dialogToolType int const ( toolNone dialogToolType = iota toolNotifySend toolKdialogPassive toolZenity toolKdialogError toolXmessage ) var ( dialogTools map[string]bool dialogToolOnce sync.Once dialogToolNames = []string{"notify-send", "kdialog", "zenity", "xmessage"} ) func init() { dialogToolOnce.Do(func() { detectDialogTools(defaultCommandRunner{}) }) } func platformStartupChannels(runner commandRunner) []promptChannel { return []promptChannel{ linuxCommandChannel("notify-send", toolNotifySend, runner, linuxHasGraphicalSessionAndDBus, func(req promptRequest) []string { return []string{"-u", "critical", "-a", appName, "-i", "nex", req.title, req.message} }), linuxCommandChannel("kdialog", toolKdialogPassive, runner, linuxHasGraphicalSession, func(req promptRequest) []string { return []string{"--title", req.title, "--passivepopup", req.message, "10"} }), linuxCommandChannel("zenity", toolZenity, runner, linuxHasGraphicalSession, func(req promptRequest) []string { return []string{"--error", fmt.Sprintf("--title=%s", req.title), fmt.Sprintf("--text=%s", req.message)} }), linuxCommandChannel("kdialog", toolKdialogError, runner, linuxHasGraphicalSession, func(req promptRequest) []string { return []string{"--title", req.title, "--error", req.message} }), linuxCommandChannel("xmessage", toolXmessage, runner, linuxHasX11Display, func(req promptRequest) []string { return []string{"-center", "-buttons", "OK:0", "-default", "OK", fmt.Sprintf("%s: %s", req.title, req.message)} }), } } func detectDialogTools(runner commandRunner) { dialogTools = make(map[string]bool, len(dialogToolNames)) for _, name := range dialogToolNames { _, err := runner.LookPath(name) dialogTools[name] = err == nil } } func linuxCommandChannel(name string, typ dialogToolType, runner commandRunner, environmentOK func() error, args func(promptRequest) []string) promptChannel { return promptChannel{ name: fmt.Sprintf("linux-%s-%d", name, typ), available: func() error { if err := linuxCommandAvailable(runner, name); err != nil { return err } return environmentOK() }, run: func(req promptRequest) error { return runner.Run(promptCommandTimeout, nil, name, args(req)...) }, } } func linuxCommandAvailable(runner commandRunner, name string) error { if _, ok := runner.(defaultCommandRunner); ok { dialogToolOnce.Do(func() { detectDialogTools(runner) }) if dialogTools[name] { return nil } return fmt.Errorf("%s 不可用", name) } _, err := runner.LookPath(name) return err } func linuxHasGraphicalSession() error { if os.Getenv("DISPLAY") == "" && os.Getenv("WAYLAND_DISPLAY") == "" { return errors.New("缺少图形会话") } return nil } func linuxHasGraphicalSessionAndDBus() error { if err := linuxHasGraphicalSession(); err != nil { return err } if os.Getenv("DBUS_SESSION_BUS_ADDRESS") == "" { return errors.New("缺少 DBus session bus") } return nil } func linuxHasX11Display() error { if os.Getenv("DISPLAY") == "" { return errors.New("缺少 X11 DISPLAY") } return nil }