diff --git a/internal/zenutil/run_unix.go b/internal/zenutil/run_unix.go index 6b7e690..df22935 100644 --- a/internal/zenutil/run_unix.go +++ b/internal/zenutil/run_unix.go @@ -8,12 +8,16 @@ import ( "os" "os/exec" "strconv" + "sync" "syscall" ) -var tool, path string +var ( + tool, path string + pathOnce sync.Once +) -func init() { +func initPath() { for _, tool = range [3]string{"qarma", "zenity", "matedialog"} { path, _ = exec.LookPath(tool) if path != "" { @@ -23,8 +27,15 @@ func init() { tool = "zenity" } +// IsAvailable is internal. +func IsAvailable() bool { + pathOnce.Do(initPath) + return path != "" +} + // Run is internal. func Run(ctx context.Context, args []string) ([]byte, error) { + pathOnce.Do(initPath) if Command && path != "" { if Timeout > 0 { args = append(args, "--timeout", strconv.Itoa(Timeout)) @@ -44,6 +55,7 @@ func Run(ctx context.Context, args []string) ([]byte, error) { // RunProgress is internal. func RunProgress(ctx context.Context, max int, extra *string, args []string) (*progressDialog, error) { + pathOnce.Do(initPath) if Command && path != "" { if Timeout > 0 { args = append(args, "--timeout", strconv.Itoa(Timeout)) diff --git a/internal/zenutil/run_unix_test.go b/internal/zenutil/run_unix_test.go index 2ab2e08..fa2edc9 100644 --- a/internal/zenutil/run_unix_test.go +++ b/internal/zenutil/run_unix_test.go @@ -41,7 +41,7 @@ func TestRunProgress(t *testing.T) { } func skip(err error) (bool, error) { - if _, ok := err.(*exec.Error); ok { + if _, ok := err.(*exec.Error); ok && !IsAvailable() { // zenity was not found in path return true, err } diff --git a/zenity.go b/zenity.go index b06b120..63ad290 100644 --- a/zenity.go +++ b/zenity.go @@ -30,6 +30,12 @@ const ErrExtraButton = zenutil.ErrExtraButton // ErrUnsupported is returned when a combination of options is not supported. const ErrUnsupported = zenutil.ErrUnsupported +// IsAvailable reports whether dependencies of the package are installed. +// It always returns true on Windows and macOS. +func IsAvailable() bool { + return isAvailable() +} + type options struct { // General options title *string @@ -182,6 +188,16 @@ func WindowIcon(icon any) Option { return funcOption(func(o *options) { o.windowIcon = icon }) } +// Attach returns an Option to set the parent window to attach to. +// +// Attach accepts: +// - a window id (int) on Unix +// - a window handle (~uintptr) on Windows +// - an application name (string) or process id (int) on macOS +func Attach(id any) Option { + return attach(id) +} + // Modal returns an Option to set the modal hint. func Modal() Option { return funcOption(func(o *options) { o.modal = true }) diff --git a/zenity_darwin.go b/zenity_darwin.go index 7feae2a..3d84344 100644 --- a/zenity_darwin.go +++ b/zenity_darwin.go @@ -1,12 +1,8 @@ package zenity -// Attach returns an Option to set the parent window to attach to. -// -// Attach accepts: -// - a window id (int) on Unix -// - a window handle (~uintptr) on Windows -// - an application name (string) or process id (int) on macOS -func Attach(id any) Option { +func isAvailable() bool { return true } + +func attach(id any) Option { switch id.(type) { case int, string: default: diff --git a/zenity_unix.go b/zenity_unix.go index 677fc04..9dfdb70 100644 --- a/zenity_unix.go +++ b/zenity_unix.go @@ -2,12 +2,10 @@ package zenity -// Attach returns an Option to set the parent window to attach to. -// -// Attach accepts: -// - a window id (int) on Unix -// - a window handle (~uintptr) on Windows -// - an application name (string) or process id (int) on macOS -func Attach(id int) Option { - return funcOption(func(o *options) { o.attach = id }) +import "github.com/ncruces/zenity/internal/zenutil" + +func isAvailable() bool { return zenutil.IsAvailable() } + +func attach(id any) Option { + return funcOption(func(o *options) { o.attach = id.(int) }) } diff --git a/zenity_windows.go b/zenity_windows.go index 4598ff7..1b0440d 100644 --- a/zenity_windows.go +++ b/zenity_windows.go @@ -6,13 +6,9 @@ import ( "github.com/ncruces/zenity/internal/win" ) -// Attach returns an Option to set the parent window to attach to. -// -// Attach accepts: -// - a window id (int) on Unix -// - a window handle (~uintptr) on Windows -// - an application name (string) or process id (int) on macOS -func Attach(id any) Option { +func isAvailable() bool { return true } + +func attach(id any) Option { if v := reflect.ValueOf(id); v.Kind() == reflect.Uintptr { id = win.HWND(uintptr(v.Uint())) } else {