commit
93e49a6b03
22 changed files with 252 additions and 202 deletions
|
@ -17,6 +17,10 @@ import (
|
||||||
|
|
||||||
//go:generate go run github.com/josephspurrier/goversioninfo/cmd/goversioninfo -platform-specific -manifest=win.manifest
|
//go:generate go run github.com/josephspurrier/goversioninfo/cmd/goversioninfo -platform-specific -manifest=win.manifest
|
||||||
|
|
||||||
|
const (
|
||||||
|
unspecified = "\x00"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Application Options
|
// Application Options
|
||||||
notification bool
|
notification bool
|
||||||
|
@ -122,14 +126,14 @@ func setupFlags() {
|
||||||
flag.BoolVar(&colorSelectionDlg, "color-selection", false, "Display color selection dialog")
|
flag.BoolVar(&colorSelectionDlg, "color-selection", false, "Display color selection dialog")
|
||||||
|
|
||||||
// General options
|
// General options
|
||||||
flag.StringVar(&title, "title", "", "Set the dialog title")
|
flag.StringVar(&title, "title", "", "Set the dialog `title`")
|
||||||
flag.StringVar(&icon, "window-icon", "", "Set the window icon (error, info, question, warning)")
|
flag.StringVar(&icon, "window-icon", "", "Set the window `icon` (error, info, question, warning)")
|
||||||
flag.UintVar(&width, "width", 0, "Set the width")
|
flag.UintVar(&width, "width", 0, "Set the `width`")
|
||||||
flag.UintVar(&height, "height", 0, "Set the height")
|
flag.UintVar(&height, "height", 0, "Set the `height`")
|
||||||
|
|
||||||
// Message options
|
// Message options
|
||||||
flag.StringVar(&text, "text", "", "Set the dialog text")
|
flag.StringVar(&text, "text", "", "Set the dialog `text`")
|
||||||
flag.StringVar(&icon, "icon-name", "", "Set the dialog icon (dialog-error, dialog-information, dialog-question, dialog-warning)")
|
flag.StringVar(&icon, "icon-name", "", "Set the dialog `icon` (dialog-error, dialog-information, dialog-question, dialog-warning)")
|
||||||
flag.StringVar(&okLabel, "ok-label", "", "Set the label of the OK button")
|
flag.StringVar(&okLabel, "ok-label", "", "Set the label of the OK button")
|
||||||
flag.StringVar(&cancelLabel, "cancel-label", "", "Set the label of the Cancel button")
|
flag.StringVar(&cancelLabel, "cancel-label", "", "Set the label of the Cancel button")
|
||||||
flag.StringVar(&extraButton, "extra-button", "", "Add an extra button")
|
flag.StringVar(&extraButton, "extra-button", "", "Add an extra button")
|
||||||
|
@ -144,11 +148,11 @@ func setupFlags() {
|
||||||
flag.BoolVar(&confirmOverwrite, "confirm-overwrite", false, "Confirm file selection if filename already exists")
|
flag.BoolVar(&confirmOverwrite, "confirm-overwrite", false, "Confirm file selection if filename already exists")
|
||||||
flag.BoolVar(&confirmCreate, "confirm-create", false, "Confirm file selection if filename does not yet exist (Windows only)")
|
flag.BoolVar(&confirmCreate, "confirm-create", false, "Confirm file selection if filename does not yet exist (Windows only)")
|
||||||
flag.BoolVar(&showHidden, "show-hidden", false, "Show hidden files (Windows and macOS only)")
|
flag.BoolVar(&showHidden, "show-hidden", false, "Show hidden files (Windows and macOS only)")
|
||||||
flag.StringVar(&filename, "filename", "", "Set the filename")
|
flag.StringVar(&filename, "filename", "", "Set the `filename`")
|
||||||
flag.Var(&fileFilters, "file-filter", "Set a filename filter (NAME | PATTERN1 PATTERN2 ...)")
|
flag.Var(&fileFilters, "file-filter", "Set a filename filter (NAME | PATTERN1 PATTERN2 ...)")
|
||||||
|
|
||||||
// Color selection options
|
// Color selection options
|
||||||
flag.StringVar(&defaultColor, "color", "", "Set the color")
|
flag.StringVar(&defaultColor, "color", "", "Set the `color`")
|
||||||
flag.BoolVar(&showPalette, "show-palette", false, "Show the palette")
|
flag.BoolVar(&showPalette, "show-palette", false, "Show the palette")
|
||||||
|
|
||||||
// Windows specific options
|
// Windows specific options
|
||||||
|
@ -157,9 +161,17 @@ func setupFlags() {
|
||||||
flag.BoolVar(&wslpath, "wslpath", false, "Use wslpath for path translation (Windows only)")
|
flag.BoolVar(&wslpath, "wslpath", false, "Use wslpath for path translation (Windows only)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal options
|
// Command options
|
||||||
flag.IntVar(&zenutil.Timeout, "timeout", 0, "Set dialog timeout in seconds")
|
flag.IntVar(&zenutil.Timeout, "timeout", 0, "Set dialog `timeout` in seconds")
|
||||||
flag.StringVar(&zenutil.Separator, "separator", "|", "Set output separator character")
|
flag.StringVar(&zenutil.Separator, "separator", "|", "Set output `separator` character")
|
||||||
|
|
||||||
|
// Detect unspecified values
|
||||||
|
title = unspecified
|
||||||
|
icon = unspecified
|
||||||
|
text = unspecified
|
||||||
|
okLabel = unspecified
|
||||||
|
cancelLabel = unspecified
|
||||||
|
extraButton = unspecified
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateFlags() {
|
func validateFlags() {
|
||||||
|
@ -193,26 +205,53 @@ func validateFlags() {
|
||||||
func loadFlags() []zenity.Option {
|
func loadFlags() []zenity.Option {
|
||||||
var opts []zenity.Option
|
var opts []zenity.Option
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
|
||||||
|
setDefault := func(s *string, val string) {
|
||||||
|
if *s == unspecified {
|
||||||
|
*s = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case errorDlg:
|
||||||
|
setDefault(&title, "Error")
|
||||||
|
setDefault(&icon, "dialog-error")
|
||||||
|
setDefault(&text, "An error has occurred.")
|
||||||
|
setDefault(&okLabel, "OK")
|
||||||
|
case infoDlg:
|
||||||
|
setDefault(&title, "Information")
|
||||||
|
setDefault(&icon, "dialog-information")
|
||||||
|
setDefault(&text, "All updates are complete.")
|
||||||
|
setDefault(&okLabel, "OK")
|
||||||
|
case warningDlg:
|
||||||
|
setDefault(&title, "Warning")
|
||||||
|
setDefault(&icon, "dialog-warning")
|
||||||
|
setDefault(&text, "Are you sure you want to proceed?")
|
||||||
|
setDefault(&okLabel, "OK")
|
||||||
|
case questionDlg:
|
||||||
|
setDefault(&title, "Question")
|
||||||
|
setDefault(&icon, "dialog-question")
|
||||||
|
setDefault(&text, "Are you sure you want to proceed?")
|
||||||
|
setDefault(&okLabel, "Yes")
|
||||||
|
setDefault(&cancelLabel, "No")
|
||||||
|
default:
|
||||||
|
setDefault(&text, "")
|
||||||
|
}
|
||||||
|
|
||||||
// General options
|
// General options
|
||||||
|
|
||||||
|
if title != unspecified {
|
||||||
opts = append(opts, zenity.Title(title))
|
opts = append(opts, zenity.Title(title))
|
||||||
|
}
|
||||||
opts = append(opts, zenity.Width(width))
|
opts = append(opts, zenity.Width(width))
|
||||||
opts = append(opts, zenity.Height(height))
|
opts = append(opts, zenity.Height(height))
|
||||||
|
|
||||||
// Message options
|
// Message options
|
||||||
|
|
||||||
var ico zenity.DialogIcon
|
var ico zenity.DialogIcon
|
||||||
switch {
|
|
||||||
case errorDlg:
|
|
||||||
ico = zenity.ErrorIcon
|
|
||||||
case infoDlg:
|
|
||||||
ico = zenity.InfoIcon
|
|
||||||
case warningDlg:
|
|
||||||
ico = zenity.WarningIcon
|
|
||||||
case questionDlg:
|
|
||||||
ico = zenity.QuestionIcon
|
|
||||||
}
|
|
||||||
switch icon {
|
switch icon {
|
||||||
|
case "":
|
||||||
|
ico = zenity.NoIcon
|
||||||
case "error", "dialog-error":
|
case "error", "dialog-error":
|
||||||
ico = zenity.ErrorIcon
|
ico = zenity.ErrorIcon
|
||||||
case "info", "dialog-information":
|
case "info", "dialog-information":
|
||||||
|
@ -224,9 +263,15 @@ func loadFlags() []zenity.Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = append(opts, zenity.Icon(ico))
|
opts = append(opts, zenity.Icon(ico))
|
||||||
|
if okLabel != unspecified {
|
||||||
opts = append(opts, zenity.OKLabel(okLabel))
|
opts = append(opts, zenity.OKLabel(okLabel))
|
||||||
|
}
|
||||||
|
if cancelLabel != unspecified {
|
||||||
opts = append(opts, zenity.CancelLabel(cancelLabel))
|
opts = append(opts, zenity.CancelLabel(cancelLabel))
|
||||||
|
}
|
||||||
|
if extraButton != unspecified {
|
||||||
opts = append(opts, zenity.ExtraButton(extraButton))
|
opts = append(opts, zenity.ExtraButton(extraButton))
|
||||||
|
}
|
||||||
if noWrap {
|
if noWrap {
|
||||||
opts = append(opts, zenity.NoWrap())
|
opts = append(opts, zenity.NoWrap())
|
||||||
}
|
}
|
||||||
|
|
2
color.go
2
color.go
|
@ -8,7 +8,7 @@ import "image/color"
|
||||||
//
|
//
|
||||||
// Valid options: Title, Color, ShowPalette.
|
// Valid options: Title, Color, ShowPalette.
|
||||||
func SelectColor(options ...Option) (color.Color, error) {
|
func SelectColor(options ...Option) (color.Color, error) {
|
||||||
return selectColor(options)
|
return selectColor(applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color returns an Option to set the color.
|
// Color returns an Option to set the color.
|
||||||
|
|
|
@ -7,9 +7,7 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func selectColor(options []Option) (color.Color, error) {
|
func selectColor(opts options) (color.Color, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var col color.Color
|
var col color.Color
|
||||||
if opts.color != nil {
|
if opts.color != nil {
|
||||||
col = opts.color
|
col = opts.color
|
||||||
|
|
|
@ -9,13 +9,11 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func selectColor(options []Option) (color.Color, error) {
|
func selectColor(opts options) (color.Color, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
args := []string{"--color-selection"}
|
args := []string{"--color-selection"}
|
||||||
|
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args = append(args, "--title", opts.title)
|
args = append(args, "--title", *opts.title)
|
||||||
}
|
}
|
||||||
if opts.color != nil {
|
if opts.color != nil {
|
||||||
args = append(args, "--color", zenutil.UnparseColor(opts.color))
|
args = append(args, "--color", zenutil.UnparseColor(opts.color))
|
||||||
|
|
|
@ -20,9 +20,7 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectColor(options []Option) (color.Color, error) {
|
func selectColor(opts options) (color.Color, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
// load custom colors
|
// load custom colors
|
||||||
colorsMutex.Lock()
|
colorsMutex.Lock()
|
||||||
customColors := savedColors
|
customColors := savedColors
|
||||||
|
@ -46,7 +44,7 @@ func selectColor(options []Option) (color.Color, error) {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
if opts.ctx != nil || opts.title != "" {
|
if opts.ctx != nil || opts.title != nil {
|
||||||
unhook, err := hookDialogTitle(opts.ctx, opts.title)
|
unhook, err := hookDialogTitle(opts.ctx, opts.title)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
6
file.go
6
file.go
|
@ -11,7 +11,7 @@ import (
|
||||||
//
|
//
|
||||||
// Valid options: Title, Directory, Filename, ShowHidden, FileFilter(s).
|
// Valid options: Title, Directory, Filename, ShowHidden, FileFilter(s).
|
||||||
func SelectFile(options ...Option) (string, error) {
|
func SelectFile(options ...Option) (string, error) {
|
||||||
return selectFile(options)
|
return selectFile(applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectFileMutiple displays the multiple file selection dialog.
|
// SelectFileMutiple displays the multiple file selection dialog.
|
||||||
|
@ -20,7 +20,7 @@ func SelectFile(options ...Option) (string, error) {
|
||||||
//
|
//
|
||||||
// Valid options: Title, Directory, Filename, ShowHidden, FileFilter(s).
|
// Valid options: Title, Directory, Filename, ShowHidden, FileFilter(s).
|
||||||
func SelectFileMutiple(options ...Option) ([]string, error) {
|
func SelectFileMutiple(options ...Option) ([]string, error) {
|
||||||
return selectFileMutiple(options)
|
return selectFileMutiple(applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectFileSave displays the save file selection dialog.
|
// SelectFileSave displays the save file selection dialog.
|
||||||
|
@ -30,7 +30,7 @@ func SelectFileMutiple(options ...Option) ([]string, error) {
|
||||||
// Valid options: Title, Filename, ConfirmOverwrite, ConfirmCreate, ShowHidden,
|
// Valid options: Title, Filename, ConfirmOverwrite, ConfirmCreate, ShowHidden,
|
||||||
// FileFilter(s).
|
// FileFilter(s).
|
||||||
func SelectFileSave(options ...Option) (string, error) {
|
func SelectFileSave(options ...Option) (string, error) {
|
||||||
return selectFileSave(options)
|
return selectFileSave(applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filename returns an Option to set the filename.
|
// Filename returns an Option to set the filename.
|
||||||
|
|
|
@ -7,9 +7,7 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func selectFile(options []Option) (string, error) {
|
func selectFile(opts options) (string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var data zenutil.File
|
var data zenutil.File
|
||||||
data.Options.Prompt = opts.title
|
data.Options.Prompt = opts.title
|
||||||
data.Options.Invisibles = opts.showHidden
|
data.Options.Invisibles = opts.showHidden
|
||||||
|
@ -35,9 +33,7 @@ func selectFile(options []Option) (string, error) {
|
||||||
return string(out), nil
|
return string(out), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileMutiple(options []Option) ([]string, error) {
|
func selectFileMutiple(opts options) ([]string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var data zenutil.File
|
var data zenutil.File
|
||||||
data.Options.Prompt = opts.title
|
data.Options.Prompt = opts.title
|
||||||
data.Options.Invisibles = opts.showHidden
|
data.Options.Invisibles = opts.showHidden
|
||||||
|
@ -68,9 +64,7 @@ func selectFileMutiple(options []Option) ([]string, error) {
|
||||||
return strings.Split(string(out), zenutil.Separator), nil
|
return strings.Split(string(out), zenutil.Separator), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileSave(options []Option) (string, error) {
|
func selectFileSave(opts options) (string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var data zenutil.File
|
var data zenutil.File
|
||||||
data.Options.Prompt = opts.title
|
data.Options.Prompt = opts.title
|
||||||
data.Options.Invisibles = opts.showHidden
|
data.Options.Invisibles = opts.showHidden
|
||||||
|
|
24
file_unix.go
24
file_unix.go
|
@ -9,15 +9,13 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func selectFile(options []Option) (string, error) {
|
func selectFile(opts options) (string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
args := []string{"--file-selection"}
|
args := []string{"--file-selection"}
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
args = append(args, "--directory")
|
args = append(args, "--directory")
|
||||||
}
|
}
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args = append(args, "--title", opts.title)
|
args = append(args, "--title", *opts.title)
|
||||||
}
|
}
|
||||||
if opts.filename != "" {
|
if opts.filename != "" {
|
||||||
args = append(args, "--filename", opts.filename)
|
args = append(args, "--filename", opts.filename)
|
||||||
|
@ -37,15 +35,13 @@ func selectFile(options []Option) (string, error) {
|
||||||
return string(out), nil
|
return string(out), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileMutiple(options []Option) ([]string, error) {
|
func selectFileMutiple(opts options) ([]string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
args := []string{"--file-selection", "--multiple", "--separator", zenutil.Separator}
|
args := []string{"--file-selection", "--multiple", "--separator", zenutil.Separator}
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
args = append(args, "--directory")
|
args = append(args, "--directory")
|
||||||
}
|
}
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args = append(args, "--title", opts.title)
|
args = append(args, "--title", *opts.title)
|
||||||
}
|
}
|
||||||
if opts.filename != "" {
|
if opts.filename != "" {
|
||||||
args = append(args, "--filename", opts.filename)
|
args = append(args, "--filename", opts.filename)
|
||||||
|
@ -65,15 +61,13 @@ func selectFileMutiple(options []Option) ([]string, error) {
|
||||||
return strings.Split(string(out), zenutil.Separator), nil
|
return strings.Split(string(out), zenutil.Separator), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileSave(options []Option) (string, error) {
|
func selectFileSave(opts options) (string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
args := []string{"--file-selection", "--save"}
|
args := []string{"--file-selection", "--save"}
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
args = append(args, "--directory")
|
args = append(args, "--directory")
|
||||||
}
|
}
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args = append(args, "--title", opts.title)
|
args = append(args, "--title", *opts.title)
|
||||||
}
|
}
|
||||||
if opts.filename != "" {
|
if opts.filename != "" {
|
||||||
args = append(args, "--filename", opts.filename)
|
args = append(args, "--filename", opts.filename)
|
||||||
|
|
|
@ -17,8 +17,7 @@ var (
|
||||||
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
|
shCreateItemFromParsingName = shell32.NewProc("SHCreateItemFromParsingName")
|
||||||
)
|
)
|
||||||
|
|
||||||
func selectFile(options []Option) (string, error) {
|
func selectFile(opts options) (string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
res, _, err := pickFolders(opts, false)
|
res, _, err := pickFolders(opts, false)
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -28,8 +27,8 @@ func selectFile(options []Option) (string, error) {
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Flags = 0x81008 // OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST|OFN_EXPLORER
|
args.Flags = 0x81008 // OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST|OFN_EXPLORER
|
||||||
|
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
||||||
|
@ -65,8 +64,7 @@ func selectFile(options []Option) (string, error) {
|
||||||
return syscall.UTF16ToString(res[:]), nil
|
return syscall.UTF16ToString(res[:]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileMutiple(options []Option) ([]string, error) {
|
func selectFileMutiple(opts options) ([]string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
_, res, err := pickFolders(opts, true)
|
_, res, err := pickFolders(opts, true)
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -76,8 +74,8 @@ func selectFileMutiple(options []Option) ([]string, error) {
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Flags = 0x81208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_EXPLORER
|
args.Flags = 0x81208 // OFN_NOCHANGEDIR|OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_EXPLORER
|
||||||
|
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.showHidden {
|
if opts.showHidden {
|
||||||
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
args.Flags |= 0x10000000 // OFN_FORCESHOWHIDDEN
|
||||||
|
@ -138,8 +136,7 @@ func selectFileMutiple(options []Option) ([]string, error) {
|
||||||
return split, nil
|
return split, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectFileSave(options []Option) (string, error) {
|
func selectFileSave(opts options) (string, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
if opts.directory {
|
if opts.directory {
|
||||||
res, _, err := pickFolders(opts, false)
|
res, _, err := pickFolders(opts, false)
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -149,8 +146,8 @@ func selectFileSave(options []Option) (string, error) {
|
||||||
args.StructSize = uint32(unsafe.Sizeof(args))
|
args.StructSize = uint32(unsafe.Sizeof(args))
|
||||||
args.Flags = 0x88808 // OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_NOREADONLYRETURN|OFN_EXPLORER
|
args.Flags = 0x88808 // OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST|OFN_NOREADONLYRETURN|OFN_EXPLORER
|
||||||
|
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.confirmOverwrite {
|
if opts.confirmOverwrite {
|
||||||
args.Flags |= 0x2 // OFN_OVERWRITEPROMPT
|
args.Flags |= 0x2 // OFN_OVERWRITEPROMPT
|
||||||
|
@ -229,8 +226,8 @@ func pickFolders(opts options, multi bool) (str string, lst []string, err error)
|
||||||
return "", nil, syscall.Errno(hr)
|
return "", nil, syscall.Errno(hr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
ptr := syscall.StringToUTF16Ptr(opts.title)
|
ptr := syscall.StringToUTF16Ptr(*opts.title)
|
||||||
dialog.Call(dialog.vtbl.SetTitle, uintptr(unsafe.Pointer(ptr)))
|
dialog.Call(dialog.vtbl.SetTitle, uintptr(unsafe.Pointer(ptr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,8 +316,8 @@ func browseForFolder(opts options) (string, []string, error) {
|
||||||
var args _BROWSEINFO
|
var args _BROWSEINFO
|
||||||
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
|
args.Flags = 0x1 // BIF_RETURNONLYFSDIRS
|
||||||
|
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args.Title = syscall.StringToUTF16Ptr(opts.title)
|
args.Title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
}
|
}
|
||||||
if opts.filename != "" {
|
if opts.filename != "" {
|
||||||
ptr := syscall.StringToUTF16Ptr(opts.filename)
|
ptr := syscall.StringToUTF16Ptr(opts.filename)
|
||||||
|
|
|
@ -28,10 +28,13 @@ if(Array.isArray(res)){res.join({{json .Separator}})}else{res.toString()}
|
||||||
var app=Application.currentApplication()
|
var app=Application.currentApplication()
|
||||||
app.includeStandardAdditions=true
|
app.includeStandardAdditions=true
|
||||||
app.activate()
|
app.activate()
|
||||||
|
ObjC.import("stdlib")
|
||||||
|
ObjC.import("stdio")
|
||||||
var res=app.{{.Operation}}({{json .Text}},{{json .Options}})
|
var res=app.{{.Operation}}({{json .Text}},{{json .Options}})
|
||||||
if(res.gaveUp){ObjC.import("stdlib")
|
if(res.gaveUp){$.exit(5)}
|
||||||
$.exit(5)}
|
if(res.buttonReturned==={{json .Extra}}){$.puts(res.buttonReturned)
|
||||||
if(res.buttonReturned==={{json .Extra}}){res.buttonReturned}else{void 0}
|
$.exit(1)}
|
||||||
|
void 0
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{define "notify" -}}
|
{{define "notify" -}}
|
||||||
var app=Application.currentApplication()
|
var app=Application.currentApplication()
|
||||||
|
|
|
@ -2,13 +2,14 @@ var app = Application.currentApplication()
|
||||||
app.includeStandardAdditions = true
|
app.includeStandardAdditions = true
|
||||||
app.activate()
|
app.activate()
|
||||||
|
|
||||||
|
ObjC.import("stdlib")
|
||||||
|
ObjC.import("stdio")
|
||||||
|
|
||||||
var res = app.{{.Operation}}({{json .Text}}, {{json .Options}})
|
var res = app.{{.Operation}}({{json .Text}}, {{json .Options}})
|
||||||
if (res.gaveUp) {
|
if (res.gaveUp) {
|
||||||
ObjC.import("stdlib")
|
|
||||||
$.exit(5)
|
$.exit(5)
|
||||||
}
|
}
|
||||||
if (res.buttonReturned === {{json .Extra}}) {
|
if (res.buttonReturned === {{json .Extra}}) {
|
||||||
res.buttonReturned
|
$.puts(res.buttonReturned)
|
||||||
} else {
|
$.exit(1)
|
||||||
void 0
|
|
||||||
}
|
}
|
|
@ -56,7 +56,7 @@ type File struct {
|
||||||
|
|
||||||
// FileOptions is internal.
|
// FileOptions is internal.
|
||||||
type FileOptions struct {
|
type FileOptions struct {
|
||||||
Prompt string `json:"withPrompt,omitempty"`
|
Prompt *string `json:"withPrompt,omitempty"`
|
||||||
Type []string `json:"ofType,omitempty"`
|
Type []string `json:"ofType,omitempty"`
|
||||||
Name string `json:"defaultName,omitempty"`
|
Name string `json:"defaultName,omitempty"`
|
||||||
Location string `json:"defaultLocation,omitempty"`
|
Location string `json:"defaultLocation,omitempty"`
|
||||||
|
@ -68,7 +68,7 @@ type FileOptions struct {
|
||||||
type Msg struct {
|
type Msg struct {
|
||||||
Operation string
|
Operation string
|
||||||
Text string
|
Text string
|
||||||
Extra string
|
Extra *string
|
||||||
Options MsgOptions
|
Options MsgOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ type Msg struct {
|
||||||
type MsgOptions struct {
|
type MsgOptions struct {
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
As string `json:"as,omitempty"`
|
As string `json:"as,omitempty"`
|
||||||
Title string `json:"withTitle,omitempty"`
|
Title *string `json:"withTitle,omitempty"`
|
||||||
Icon string `json:"withIcon,omitempty"`
|
Icon string `json:"withIcon,omitempty"`
|
||||||
Buttons []string `json:"buttons,omitempty"`
|
Buttons []string `json:"buttons,omitempty"`
|
||||||
Cancel int `json:"cancelButton,omitempty"`
|
Cancel int `json:"cancelButton,omitempty"`
|
||||||
|
@ -92,6 +92,6 @@ type Notify struct {
|
||||||
|
|
||||||
// NotifyOptions is internal.
|
// NotifyOptions is internal.
|
||||||
type NotifyOptions struct {
|
type NotifyOptions struct {
|
||||||
Title string `json:"withTitle,omitempty"`
|
Title *string `json:"withTitle,omitempty"`
|
||||||
Subtitle string `json:"subtitle,omitempty"`
|
Subtitle string `json:"subtitle,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
22
msg.go
22
msg.go
|
@ -2,7 +2,7 @@ package zenity
|
||||||
|
|
||||||
// ErrExtraButton is returned by dialog functions when the extra button is
|
// ErrExtraButton is returned by dialog functions when the extra button is
|
||||||
// pressed.
|
// pressed.
|
||||||
const ErrExtraButton = constError("Extra button pressed")
|
const ErrExtraButton = stringErr("Extra button pressed")
|
||||||
|
|
||||||
// Question displays the question dialog.
|
// Question displays the question dialog.
|
||||||
//
|
//
|
||||||
|
@ -11,7 +11,7 @@ const ErrExtraButton = constError("Extra button pressed")
|
||||||
// Valid options: Title, Width, Height, Icon, OKLabel, CancelLabel,
|
// Valid options: Title, Width, Height, Icon, OKLabel, CancelLabel,
|
||||||
// ExtraButton, NoWrap, Ellipsize, DefaultCancel.
|
// ExtraButton, NoWrap, Ellipsize, DefaultCancel.
|
||||||
func Question(text string, options ...Option) (bool, error) {
|
func Question(text string, options ...Option) (bool, error) {
|
||||||
return message(questionKind, text, options)
|
return message(questionKind, text, applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info displays the info dialog.
|
// Info displays the info dialog.
|
||||||
|
@ -21,7 +21,7 @@ func Question(text string, options ...Option) (bool, error) {
|
||||||
// Valid options: Title, Width, Height, Icon, OKLabel, ExtraButton,
|
// Valid options: Title, Width, Height, Icon, OKLabel, ExtraButton,
|
||||||
// NoWrap, Ellipsize.
|
// NoWrap, Ellipsize.
|
||||||
func Info(text string, options ...Option) (bool, error) {
|
func Info(text string, options ...Option) (bool, error) {
|
||||||
return message(infoKind, text, options)
|
return message(infoKind, text, applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning displays the warning dialog.
|
// Warning displays the warning dialog.
|
||||||
|
@ -31,7 +31,7 @@ func Info(text string, options ...Option) (bool, error) {
|
||||||
// Valid options: Title, Width, Height, Icon, OKLabel, ExtraButton,
|
// Valid options: Title, Width, Height, Icon, OKLabel, ExtraButton,
|
||||||
// NoWrap, Ellipsize.
|
// NoWrap, Ellipsize.
|
||||||
func Warning(text string, options ...Option) (bool, error) {
|
func Warning(text string, options ...Option) (bool, error) {
|
||||||
return message(warningKind, text, options)
|
return message(warningKind, text, applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error displays the error dialog.
|
// Error displays the error dialog.
|
||||||
|
@ -41,7 +41,7 @@ func Warning(text string, options ...Option) (bool, error) {
|
||||||
// Valid options: Title, Width, Height, Icon, OKLabel, ExtraButton,
|
// Valid options: Title, Width, Height, Icon, OKLabel, ExtraButton,
|
||||||
// NoWrap, Ellipsize.
|
// NoWrap, Ellipsize.
|
||||||
func Error(text string, options ...Option) (bool, error) {
|
func Error(text string, options ...Option) (bool, error) {
|
||||||
return message(errorKind, text, options)
|
return message(errorKind, text, applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
||||||
type messageKind int
|
type messageKind int
|
||||||
|
@ -55,30 +55,30 @@ const (
|
||||||
|
|
||||||
// OKLabel returns an Option to set the label of the OK button.
|
// OKLabel returns an Option to set the label of the OK button.
|
||||||
func OKLabel(ok string) Option {
|
func OKLabel(ok string) Option {
|
||||||
return funcOption(func(o *options) { o.okLabel = ok })
|
return funcOption(func(o *options) { o.okLabel = &ok })
|
||||||
}
|
}
|
||||||
|
|
||||||
// CancelLabel returns an Option to set the label of the Cancel button.
|
// CancelLabel returns an Option to set the label of the Cancel button.
|
||||||
func CancelLabel(cancel string) Option {
|
func CancelLabel(cancel string) Option {
|
||||||
return funcOption(func(o *options) { o.cancelLabel = cancel })
|
return funcOption(func(o *options) { o.cancelLabel = &cancel })
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtraButton returns an Option to add an extra button.
|
// ExtraButton returns an Option to add an extra button.
|
||||||
func ExtraButton(extra string) Option {
|
func ExtraButton(extra string) Option {
|
||||||
return funcOption(func(o *options) { o.extraButton = extra })
|
return funcOption(func(o *options) { o.extraButton = &extra })
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoWrap returns an Option to disable enable text wrapping.
|
// NoWrap returns an Option to disable enable text wrapping (Unix only).
|
||||||
func NoWrap() Option {
|
func NoWrap() Option {
|
||||||
return funcOption(func(o *options) { o.noWrap = true })
|
return funcOption(func(o *options) { o.noWrap = true })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ellipsize returns an Option to enable ellipsizing in the dialog text.
|
// Ellipsize returns an Option to enable ellipsizing in the dialog text (Unix only).
|
||||||
func Ellipsize() Option {
|
func Ellipsize() Option {
|
||||||
return funcOption(func(o *options) { o.ellipsize = true })
|
return funcOption(func(o *options) { o.ellipsize = true })
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultCancel returns an Option to give Cancel button focus by default.
|
// DefaultCancel returns an Option to give the Cancel button focus by default.
|
||||||
func DefaultCancel() Option {
|
func DefaultCancel() Option {
|
||||||
return funcOption(func(o *options) { o.defaultCancel = true })
|
return funcOption(func(o *options) { o.defaultCancel = true })
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,18 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func message(kind messageKind, text string, options []Option) (bool, error) {
|
func message(kind messageKind, text string, opts options) (bool, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var data zenutil.Msg
|
var data zenutil.Msg
|
||||||
data.Text = text
|
data.Text = text
|
||||||
data.Options.Timeout = zenutil.Timeout
|
data.Options.Timeout = zenutil.Timeout
|
||||||
|
|
||||||
dialog := kind == questionKind || opts.icon != 0
|
// dialog is more flexible, alert prettier
|
||||||
|
var dialog bool
|
||||||
|
if opts.icon != 0 { // use if we want to show a specific icon
|
||||||
|
dialog = true
|
||||||
|
} else if kind == questionKind && opts.cancelLabel == nil { // use for questions with default buttons
|
||||||
|
dialog = true
|
||||||
|
}
|
||||||
|
|
||||||
if dialog {
|
if dialog {
|
||||||
data.Operation = "displayDialog"
|
data.Operation = "displayDialog"
|
||||||
|
@ -29,9 +33,9 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data.Operation = "displayAlert"
|
data.Operation = "displayAlert"
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
|
data.Text = *opts.title
|
||||||
data.Options.Message = text
|
data.Options.Message = text
|
||||||
data.Text = opts.title
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
|
@ -44,58 +48,67 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind != questionKind {
|
if kind == questionKind {
|
||||||
if dialog {
|
// alert defaults to a single button, we need two
|
||||||
opts.okLabel = "OK"
|
if opts.cancelLabel == nil && !dialog {
|
||||||
|
opts.cancelLabel = stringPtr("Cancel")
|
||||||
}
|
}
|
||||||
opts.cancelLabel = ""
|
} else {
|
||||||
|
// dialog defaults to two buttons, we need one
|
||||||
|
if opts.okLabel == nil && dialog {
|
||||||
|
opts.okLabel = stringPtr("OK")
|
||||||
}
|
}
|
||||||
if opts.okLabel != "" || opts.cancelLabel != "" || opts.extraButton != "" {
|
// only questions have cancel
|
||||||
if opts.okLabel == "" {
|
opts.cancelLabel = nil
|
||||||
opts.okLabel = "OK"
|
|
||||||
}
|
}
|
||||||
if opts.cancelLabel == "" {
|
|
||||||
opts.cancelLabel = "Cancel"
|
if opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil {
|
||||||
|
if opts.okLabel == nil {
|
||||||
|
opts.okLabel = stringPtr("OK")
|
||||||
}
|
}
|
||||||
if kind == questionKind {
|
if kind == questionKind {
|
||||||
if opts.extraButton == "" {
|
if opts.cancelLabel == nil {
|
||||||
data.Options.Buttons = []string{opts.cancelLabel, opts.okLabel}
|
opts.cancelLabel = stringPtr("Cancel")
|
||||||
|
}
|
||||||
|
if opts.extraButton == nil {
|
||||||
|
data.Options.Buttons = []string{*opts.cancelLabel, *opts.okLabel}
|
||||||
data.Options.Default = 2
|
data.Options.Default = 2
|
||||||
data.Options.Cancel = 1
|
data.Options.Cancel = 1
|
||||||
} else {
|
} else {
|
||||||
data.Options.Buttons = []string{opts.extraButton, opts.cancelLabel, opts.okLabel}
|
data.Options.Buttons = []string{*opts.extraButton, *opts.cancelLabel, *opts.okLabel}
|
||||||
data.Options.Default = 3
|
data.Options.Default = 3
|
||||||
data.Options.Cancel = 2
|
data.Options.Cancel = 2
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if opts.extraButton == "" {
|
if opts.extraButton == nil {
|
||||||
data.Options.Buttons = []string{opts.okLabel}
|
data.Options.Buttons = []string{*opts.okLabel}
|
||||||
data.Options.Default = 1
|
data.Options.Default = 1
|
||||||
} else {
|
} else {
|
||||||
data.Options.Buttons = []string{opts.extraButton, opts.okLabel}
|
data.Options.Buttons = []string{*opts.extraButton, *opts.okLabel}
|
||||||
data.Options.Default = 2
|
data.Options.Default = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.Extra = opts.extraButton
|
data.Extra = opts.extraButton
|
||||||
}
|
}
|
||||||
if opts.defaultCancel {
|
|
||||||
|
if kind == questionKind && opts.defaultCancel {
|
||||||
if data.Options.Cancel != 0 {
|
if data.Options.Cancel != 0 {
|
||||||
data.Options.Default = data.Options.Cancel
|
data.Options.Default = data.Options.Cancel
|
||||||
}
|
} else {
|
||||||
if dialog && data.Options.Buttons == nil {
|
|
||||||
data.Options.Default = 1
|
data.Options.Default = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := zenutil.Run(opts.ctx, "msg", data)
|
out, err := zenutil.Run(opts.ctx, "msg", data)
|
||||||
|
if len(out) > 0 && opts.extraButton != nil &&
|
||||||
|
string(out[:len(out)-1]) == *opts.extraButton {
|
||||||
|
return false, ErrExtraButton
|
||||||
|
}
|
||||||
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
|
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if len(out) > 0 && string(out[:len(out)-1]) == opts.extraButton {
|
|
||||||
return false, ErrExtraButton
|
|
||||||
}
|
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
27
msg_unix.go
27
msg_unix.go
|
@ -9,9 +9,7 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func message(kind messageKind, text string, options []Option) (bool, error) {
|
func message(kind messageKind, text string, opts options) (bool, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var args []string
|
var args []string
|
||||||
switch kind {
|
switch kind {
|
||||||
case questionKind:
|
case questionKind:
|
||||||
|
@ -26,8 +24,8 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
if text != "" {
|
if text != "" {
|
||||||
args = append(args, "--text", text, "--no-markup")
|
args = append(args, "--text", text, "--no-markup")
|
||||||
}
|
}
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args = append(args, "--title", opts.title)
|
args = append(args, "--title", *opts.title)
|
||||||
}
|
}
|
||||||
if opts.width > 0 {
|
if opts.width > 0 {
|
||||||
args = append(args, "--width", strconv.FormatUint(uint64(opts.width), 10))
|
args = append(args, "--width", strconv.FormatUint(uint64(opts.width), 10))
|
||||||
|
@ -35,14 +33,14 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
if opts.height > 0 {
|
if opts.height > 0 {
|
||||||
args = append(args, "--height", strconv.FormatUint(uint64(opts.height), 10))
|
args = append(args, "--height", strconv.FormatUint(uint64(opts.height), 10))
|
||||||
}
|
}
|
||||||
if opts.okLabel != "" {
|
if opts.okLabel != nil {
|
||||||
args = append(args, "--ok-label", opts.okLabel)
|
args = append(args, "--ok-label", *opts.okLabel)
|
||||||
}
|
}
|
||||||
if opts.cancelLabel != "" {
|
if opts.cancelLabel != nil {
|
||||||
args = append(args, "--cancel-label", opts.cancelLabel)
|
args = append(args, "--cancel-label", *opts.cancelLabel)
|
||||||
}
|
}
|
||||||
if opts.extraButton != "" {
|
if opts.extraButton != nil {
|
||||||
args = append(args, "--extra-button", opts.extraButton)
|
args = append(args, "--extra-button", *opts.extraButton)
|
||||||
}
|
}
|
||||||
if opts.noWrap {
|
if opts.noWrap {
|
||||||
args = append(args, "--no-wrap")
|
args = append(args, "--no-wrap")
|
||||||
|
@ -54,6 +52,8 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
args = append(args, "--default-cancel")
|
args = append(args, "--default-cancel")
|
||||||
}
|
}
|
||||||
switch opts.icon {
|
switch opts.icon {
|
||||||
|
case NoIcon:
|
||||||
|
args = append(args, "--icon-name=")
|
||||||
case ErrorIcon:
|
case ErrorIcon:
|
||||||
args = append(args, "--window-icon=error", "--icon-name=dialog-error")
|
args = append(args, "--window-icon=error", "--icon-name=dialog-error")
|
||||||
case WarningIcon:
|
case WarningIcon:
|
||||||
|
@ -65,10 +65,11 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := zenutil.Run(opts.ctx, args)
|
out, err := zenutil.Run(opts.ctx, args)
|
||||||
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() != 255 {
|
if len(out) > 0 && opts.extraButton != nil &&
|
||||||
if len(out) > 0 && string(out[:len(out)-1]) == opts.extraButton {
|
string(out[:len(out)-1]) == *opts.extraButton {
|
||||||
return false, ErrExtraButton
|
return false, ErrExtraButton
|
||||||
}
|
}
|
||||||
|
if err, ok := err.(*exec.ExitError); ok && err.ExitCode() == 1 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,16 +11,16 @@ var (
|
||||||
messageBox = user32.NewProc("MessageBoxW")
|
messageBox = user32.NewProc("MessageBoxW")
|
||||||
)
|
)
|
||||||
|
|
||||||
func message(kind messageKind, text string, options []Option) (bool, error) {
|
func message(kind messageKind, text string, opts options) (bool, error) {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var flags uintptr
|
var flags uintptr
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case kind == questionKind && opts.extraButton != "":
|
case kind == questionKind && opts.extraButton != nil:
|
||||||
flags |= 0x3 // MB_YESNOCANCEL
|
flags |= 0x3 // MB_YESNOCANCEL
|
||||||
case kind == questionKind || opts.extraButton != "":
|
case kind == questionKind:
|
||||||
flags |= 0x1 // MB_OKCANCEL
|
flags |= 0x1 // MB_OKCANCEL
|
||||||
|
case opts.extraButton != nil:
|
||||||
|
flags |= 0x4 // MB_YESNO
|
||||||
}
|
}
|
||||||
|
|
||||||
switch opts.icon {
|
switch opts.icon {
|
||||||
|
@ -35,14 +35,14 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind == questionKind && opts.defaultCancel {
|
if kind == questionKind && opts.defaultCancel {
|
||||||
if opts.extraButton == "" {
|
if opts.extraButton == nil {
|
||||||
flags |= 0x100 // MB_DEFBUTTON2
|
flags |= 0x100 // MB_DEFBUTTON2
|
||||||
} else {
|
} else {
|
||||||
flags |= 0x200 // MB_DEFBUTTON3
|
flags |= 0x200 // MB_DEFBUTTON3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.ctx != nil || opts.okLabel != "" || opts.cancelLabel != "" || opts.extraButton != "" {
|
if opts.ctx != nil || opts.okLabel != nil || opts.cancelLabel != nil || opts.extraButton != nil {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
@ -53,24 +53,29 @@ func message(kind messageKind, text string, options []Option) (bool, error) {
|
||||||
defer unhook()
|
defer unhook()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var title *uint16
|
||||||
|
if opts.title != nil {
|
||||||
|
title = syscall.StringToUTF16Ptr(*opts.title)
|
||||||
|
}
|
||||||
|
|
||||||
activate()
|
activate()
|
||||||
s, _, err := messageBox.Call(0,
|
s, _, err := messageBox.Call(0,
|
||||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
|
||||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(opts.title))), flags)
|
uintptr(unsafe.Pointer(title)), flags)
|
||||||
|
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return false, opts.ctx.Err()
|
return false, opts.ctx.Err()
|
||||||
}
|
}
|
||||||
if s == 0 {
|
switch s {
|
||||||
|
case 1, 6: // IDOK, IDYES
|
||||||
|
return true, nil
|
||||||
|
case 2: // IDCANCEL
|
||||||
|
return false, nil
|
||||||
|
case 7: // IDNO
|
||||||
|
return false, ErrExtraButton
|
||||||
|
default:
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if s == 7 || s == 2 && kind != questionKind { // IDNO
|
|
||||||
return false, ErrExtraButton
|
|
||||||
}
|
|
||||||
if s == 1 || s == 6 { // IDOK, IDYES
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hookMessageLabels(kind messageKind, opts options) (unhook context.CancelFunc, err error) {
|
func hookMessageLabels(kind messageKind, opts options) (unhook context.CancelFunc, err error) {
|
||||||
|
@ -81,23 +86,21 @@ func hookMessageLabels(kind messageKind, opts options) (unhook context.CancelFun
|
||||||
getClassName.Call(wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
|
getClassName.Call(wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
|
||||||
if syscall.UTF16ToString(name[:]) == "Button" {
|
if syscall.UTF16ToString(name[:]) == "Button" {
|
||||||
ctl, _, _ := getDlgCtrlID.Call(wnd)
|
ctl, _, _ := getDlgCtrlID.Call(wnd)
|
||||||
var text string
|
var text *string
|
||||||
switch ctl {
|
switch ctl {
|
||||||
case 1, 6: // IDOK, IDYES
|
case 1, 6: // IDOK, IDYES
|
||||||
text = opts.okLabel
|
text = opts.okLabel
|
||||||
case 2: // IDCANCEL
|
case 2: // IDCANCEL
|
||||||
if kind == questionKind {
|
if kind == questionKind {
|
||||||
text = opts.cancelLabel
|
text = opts.cancelLabel
|
||||||
} else if opts.extraButton != "" {
|
|
||||||
text = opts.extraButton
|
|
||||||
} else {
|
} else {
|
||||||
text = opts.okLabel
|
text = opts.okLabel
|
||||||
}
|
}
|
||||||
case 7: // IDNO
|
case 7: // IDNO
|
||||||
text = opts.extraButton
|
text = opts.extraButton
|
||||||
}
|
}
|
||||||
if text != "" {
|
if text != nil {
|
||||||
ptr := syscall.StringToUTF16Ptr(text)
|
ptr := syscall.StringToUTF16Ptr(*text)
|
||||||
setWindowText.Call(wnd, uintptr(unsafe.Pointer(ptr)))
|
setWindowText.Call(wnd, uintptr(unsafe.Pointer(ptr)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ package zenity
|
||||||
//
|
//
|
||||||
// Valid options: Title, Icon.
|
// Valid options: Title, Icon.
|
||||||
func Notify(text string, options ...Option) error {
|
func Notify(text string, options ...Option) error {
|
||||||
return notify(text, options)
|
return notify(text, applyOptions(options))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,7 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func notify(text string, options []Option) error {
|
func notify(text string, opts options) error {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
var data zenutil.Notify
|
var data zenutil.Notify
|
||||||
data.Text = text
|
data.Text = text
|
||||||
data.Options.Title = opts.title
|
data.Options.Title = opts.title
|
||||||
|
|
|
@ -6,26 +6,26 @@ import (
|
||||||
"github.com/ncruces/zenity/internal/zenutil"
|
"github.com/ncruces/zenity/internal/zenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func notify(text string, options []Option) error {
|
func notify(text string, opts options) error {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
args := []string{"--notification"}
|
args := []string{"--notification"}
|
||||||
|
|
||||||
if text != "" {
|
if text != "" {
|
||||||
args = append(args, "--text", text, "--no-markup")
|
args = append(args, "--text", text, "--no-markup")
|
||||||
}
|
}
|
||||||
if opts.title != "" {
|
if opts.title != nil {
|
||||||
args = append(args, "--title", opts.title)
|
args = append(args, "--title", *opts.title)
|
||||||
}
|
}
|
||||||
switch opts.icon {
|
switch opts.icon {
|
||||||
|
case NoIcon:
|
||||||
|
args = append(args, "--window-icon=dialog")
|
||||||
case ErrorIcon:
|
case ErrorIcon:
|
||||||
args = append(args, "--window-icon=error")
|
args = append(args, "--window-icon=dialog-error")
|
||||||
case WarningIcon:
|
case WarningIcon:
|
||||||
args = append(args, "--window-icon=warning")
|
args = append(args, "--window-icon=dialog-warning")
|
||||||
case InfoIcon:
|
case InfoIcon:
|
||||||
args = append(args, "--window-icon=info")
|
args = append(args, "--window-icon=dialog-information")
|
||||||
case QuestionIcon:
|
case QuestionIcon:
|
||||||
args = append(args, "--window-icon=question")
|
args = append(args, "--window-icon=dialog-question")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := zenutil.Run(opts.ctx, args)
|
_, err := zenutil.Run(opts.ctx, args)
|
||||||
|
|
|
@ -13,9 +13,7 @@ var (
|
||||||
wtsSendMessage = wtsapi32.NewProc("WTSSendMessageW")
|
wtsSendMessage = wtsapi32.NewProc("WTSSendMessageW")
|
||||||
)
|
)
|
||||||
|
|
||||||
func notify(text string, options []Option) error {
|
func notify(text string, opts options) error {
|
||||||
opts := applyOptions(options)
|
|
||||||
|
|
||||||
if opts.ctx != nil && opts.ctx.Err() != nil {
|
if opts.ctx != nil && opts.ctx.Err() != nil {
|
||||||
return opts.ctx.Err()
|
return opts.ctx.Err()
|
||||||
}
|
}
|
||||||
|
@ -29,11 +27,13 @@ func notify(text string, options []Option) error {
|
||||||
info := syscall.StringToUTF16(text)
|
info := syscall.StringToUTF16(text)
|
||||||
copy(args.Info[:len(args.Info)-1], info)
|
copy(args.Info[:len(args.Info)-1], info)
|
||||||
|
|
||||||
title := syscall.StringToUTF16(opts.title)
|
if opts.title != nil {
|
||||||
|
title := syscall.StringToUTF16(*opts.title)
|
||||||
copy(args.InfoTitle[:len(args.InfoTitle)-1], title)
|
copy(args.InfoTitle[:len(args.InfoTitle)-1], title)
|
||||||
|
}
|
||||||
|
|
||||||
switch opts.icon {
|
switch opts.icon {
|
||||||
case InfoIcon:
|
case InfoIcon, QuestionIcon:
|
||||||
args.InfoFlags |= 0x1 // NIIF_INFO
|
args.InfoFlags |= 0x1 // NIIF_INFO
|
||||||
case WarningIcon:
|
case WarningIcon:
|
||||||
args.InfoFlags |= 0x2 // NIIF_WARNING
|
args.InfoFlags |= 0x2 // NIIF_WARNING
|
||||||
|
@ -71,8 +71,8 @@ func wtsMessage(text string, opts options) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
title := opts.title
|
title := opts.title
|
||||||
if title == "" {
|
if title == nil {
|
||||||
title = "Notification"
|
title = stringPtr("Notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout := zenutil.Timeout
|
timeout := zenutil.Timeout
|
||||||
|
@ -81,7 +81,7 @@ func wtsMessage(text string, opts options) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
ptext := syscall.StringToUTF16(text)
|
ptext := syscall.StringToUTF16(text)
|
||||||
ptitle := syscall.StringToUTF16(title)
|
ptitle := syscall.StringToUTF16(*title)
|
||||||
|
|
||||||
var res uint32
|
var res uint32
|
||||||
s, _, err := wtsSendMessage.Call(
|
s, _, err := wtsSendMessage.Call(
|
||||||
|
|
|
@ -138,11 +138,15 @@ func hookDialog(ctx context.Context, initDialog func(wnd uintptr)) (unhook conte
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hookDialogTitle(ctx context.Context, title string) (unhook context.CancelFunc, err error) {
|
func hookDialogTitle(ctx context.Context, title *string) (unhook context.CancelFunc, err error) {
|
||||||
return hookDialog(ctx, func(wnd uintptr) {
|
var init func(wnd uintptr)
|
||||||
ptr := syscall.StringToUTF16Ptr(title)
|
if title != nil {
|
||||||
|
init = func(wnd uintptr) {
|
||||||
|
ptr := syscall.StringToUTF16Ptr(*title)
|
||||||
setWindowText.Call(wnd, uintptr(unsafe.Pointer(ptr)))
|
setWindowText.Call(wnd, uintptr(unsafe.Pointer(ptr)))
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
return hookDialog(ctx, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
type _COMObject struct{}
|
type _COMObject struct{}
|
||||||
|
|
17
zenity.go
17
zenity.go
|
@ -15,13 +15,15 @@ import (
|
||||||
"image/color"
|
"image/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
type constError string
|
type stringErr string
|
||||||
|
|
||||||
func (e constError) Error() string { return string(e) }
|
func (e stringErr) Error() string { return string(e) }
|
||||||
|
|
||||||
|
func stringPtr(s string) *string { return &s }
|
||||||
|
|
||||||
type options struct {
|
type options struct {
|
||||||
// General options
|
// General options
|
||||||
title string
|
title *string
|
||||||
width uint
|
width uint
|
||||||
height uint
|
height uint
|
||||||
|
|
||||||
|
@ -39,9 +41,9 @@ type options struct {
|
||||||
|
|
||||||
// Message options
|
// Message options
|
||||||
icon DialogIcon
|
icon DialogIcon
|
||||||
okLabel string
|
okLabel *string
|
||||||
cancelLabel string
|
cancelLabel *string
|
||||||
extraButton string
|
extraButton *string
|
||||||
noWrap bool
|
noWrap bool
|
||||||
ellipsize bool
|
ellipsize bool
|
||||||
defaultCancel bool
|
defaultCancel bool
|
||||||
|
@ -69,7 +71,7 @@ func applyOptions(options []Option) (res options) {
|
||||||
|
|
||||||
// Title returns an Option to set the dialog title.
|
// Title returns an Option to set the dialog title.
|
||||||
func Title(title string) Option {
|
func Title(title string) Option {
|
||||||
return funcOption(func(o *options) { o.title = title })
|
return funcOption(func(o *options) { o.title = &title })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Width returns an Option to set the dialog width (Unix only).
|
// Width returns an Option to set the dialog width (Unix only).
|
||||||
|
@ -95,6 +97,7 @@ const (
|
||||||
WarningIcon
|
WarningIcon
|
||||||
InfoIcon
|
InfoIcon
|
||||||
QuestionIcon
|
QuestionIcon
|
||||||
|
NoIcon
|
||||||
)
|
)
|
||||||
|
|
||||||
// Icon returns an Option to set the dialog icon.
|
// Icon returns an Option to set the dialog icon.
|
||||||
|
|
Loading…
Reference in a new issue