WIP: zenity command (windows).

This commit is contained in:
Nuno Cruces 2020-01-09 00:54:34 +00:00
parent 7f608be6c2
commit 1fc55eed81
13 changed files with 141 additions and 34 deletions

View file

@ -1 +1,2 @@
zenity zenity
*.syso

View file

@ -11,6 +11,8 @@ import (
"github.com/ncruces/zenity/internal/cmd" "github.com/ncruces/zenity/internal/cmd"
) )
//go:generate go run github.com/josephspurrier/goversioninfo/cmd/goversioninfo -platform-specific -manifest=win.manifest
var ( var (
// Application Options // Application Options
errorDlg bool errorDlg bool
@ -58,6 +60,18 @@ func main() {
msgResult(zenity.Warning(text, opts...)) msgResult(zenity.Warning(text, opts...))
case questionDlg: case questionDlg:
msgResult(zenity.Question(text, opts...)) msgResult(zenity.Question(text, opts...))
case fileSelectionDlg:
switch {
default:
strResult(zenity.SelectFile(opts...))
case save:
strResult(zenity.SelectFileSave(opts...))
case directory:
strResult(zenity.SelectDirectory(opts...))
case multiple:
lstResult(zenity.SelectFileMutiple(opts...))
}
} }
flag.Usage() flag.Usage()
@ -95,7 +109,7 @@ func setupFlags() {
flag.BoolVar(&directory, "directory", false, "Activate directory-only selection") flag.BoolVar(&directory, "directory", false, "Activate directory-only selection")
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.StringVar(&filename, "filename", "", "Set the filename") flag.StringVar(&filename, "filename", "", "Set the filename")
flag.StringVar(&separator, "separator", "", "Set output separator character") flag.StringVar(&separator, "separator", "|", "Set output separator character")
flag.Var(&fileFilters, "file-filter", "Set a filename filter (NAME | PATTERN1 PATTERN2 ...)") flag.Var(&fileFilters, "file-filter", "Set a filename filter (NAME | PATTERN1 PATTERN2 ...)")
} }
@ -157,6 +171,16 @@ func loadFlags() []zenity.Option {
options = append(options, zenity.DefaultCancel) options = append(options, zenity.DefaultCancel)
} }
// File selection options
options = append(options, fileFilters.New())
options = append(options, zenity.Filename(filename))
if confirmOverwrite {
options = append(options, zenity.ConfirmOverwrite)
}
cmd.Separator = separator
return options return options
} }
@ -177,8 +201,36 @@ func msgResult(ok bool, err error) {
os.Exit(1) os.Exit(1)
} }
func strResult(s string, err error) {
if err != nil {
os.Stderr.WriteString(err.Error())
os.Stderr.WriteString(cmd.LineBreak)
os.Exit(-1)
}
if s == "" {
os.Exit(1)
}
os.Stdout.WriteString(s)
os.Stdout.WriteString(cmd.LineBreak)
os.Exit(0)
}
func lstResult(l []string, err error) {
if err != nil {
os.Stderr.WriteString(err.Error())
os.Stderr.WriteString(cmd.LineBreak)
os.Exit(-1)
}
os.Stdout.WriteString(strings.Join(l, separator))
os.Stdout.WriteString(cmd.LineBreak)
if l == nil {
os.Exit(1)
}
os.Exit(0)
}
type FileFilters struct { type FileFilters struct {
list []zenity.FileFilter zenity.FileFilters
} }
func (f *FileFilters) String() string { func (f *FileFilters) String() string {
@ -193,8 +245,8 @@ func (f *FileFilters) Set(s string) error {
s = split[1] s = split[1]
} }
filter.Exts = strings.Split(s, " ") filter.Patterns = strings.Split(s, " ")
f.list = append(f.list, filter) f.FileFilters = append(f.FileFilters, filter)
return nil return nil
} }

View file

@ -0,0 +1,41 @@
{
"FixedFileInfo": {
"FileVersion": {
"Major": 0,
"Minor": 0,
"Patch": 0,
"Build": 0
},
"ProductVersion": {
"Major": 0,
"Minor": 0,
"Patch": 0,
"Build": 0
},
"FileFlagsMask": "3f",
"FileFlags ": "00",
"FileOS": "040004",
"FileType": "01",
"FileSubType": "00"
},
"StringFileInfo": {
"Comments": "zenity",
"CompanyName": "Nuno Cruces",
"FileDescription": "",
"FileVersion": "0.0.0.0",
"InternalName": "zenity",
"LegalCopyright": "© 2020 Nuno Cruces",
"LegalTrademarks": "",
"OriginalFilename": "zenity.exe",
"PrivateBuild": "",
"ProductName": "zenity",
"ProductVersion": "0.0.0",
"SpecialBuild": ""
},
"VarFileInfo": {
"Translation": {
"LangID": "0409",
"CharsetID": "04B0"
}
}
}

9
cmd/zenity/win.manifest Normal file
View file

@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View file

@ -92,8 +92,8 @@ func SelectDirectory(options ...Option) (string, error) {
func appleFilters(filters []FileFilter) []string { func appleFilters(filters []FileFilter) []string {
var filter []string var filter []string
for _, f := range filters { for _, f := range filters {
for _, e := range f.Exts { for _, p := range f.Patterns {
filter = append(filter, strings.TrimPrefix(e, ".")) filter = append(filter, p) // FIXME
} }
} }
return filter return filter

View file

@ -6,9 +6,9 @@ const defaultPath = ""
func TestSelectFile(t *testing.T) { func TestSelectFile(t *testing.T) {
res, err := SelectFile(Filename(defaultPath), FileFilters{ res, err := SelectFile(Filename(defaultPath), FileFilters{
{"Go files", []string{".go"}}, {"Go files", []string{"*.go"}},
{"Web files", []string{".html", ".js", ".css"}}, {"Web files", []string{"*.html", "*.js", "*.css"}},
{"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}}, {"Image files", []string{"*.png", "*.gif", "*.ico", "*.jpg", "*.webp"}},
}.New()) }.New())
if err != nil { if err != nil {
@ -20,9 +20,9 @@ func TestSelectFile(t *testing.T) {
func TestSelectFileMutiple(t *testing.T) { func TestSelectFileMutiple(t *testing.T) {
res, err := SelectFileMutiple(Filename(defaultPath), FileFilters{ res, err := SelectFileMutiple(Filename(defaultPath), FileFilters{
{"Go files", []string{".go"}}, {"Go files", []string{"*.go"}},
{"Web files", []string{".html", ".js", ".css"}}, {"Web files", []string{"*.html", "*.js", "*.css"}},
{"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}}, {"Image files", []string{"*.png", "*.gif", "*.ico", "*.jpg", "*.webp"}},
}.New()) }.New())
if err != nil { if err != nil {
@ -34,9 +34,9 @@ func TestSelectFileMutiple(t *testing.T) {
func TestSelectFileSave(t *testing.T) { func TestSelectFileSave(t *testing.T) {
res, err := SelectFileSave(Filename(defaultPath), ConfirmOverwrite, FileFilters{ res, err := SelectFileSave(Filename(defaultPath), ConfirmOverwrite, FileFilters{
{"Go files", []string{".go"}}, {"Go files", []string{"*.go"}},
{"Web files", []string{".html", ".js", ".css"}}, {"Web files", []string{"*.html", "*.js", "*.css"}},
{"Image files", []string{".png", ".gif", ".ico", ".jpg", ".webp"}}, {"Image files", []string{"*.png", "*.gif", "*.ico", "*.jpg", "*.webp"}},
}.New()) }.New())
if err != nil { if err != nil {

View file

@ -118,9 +118,8 @@ func zenityFilters(filters []FileFilter) []string {
buf.WriteString(f.Name) buf.WriteString(f.Name)
buf.WriteRune('|') buf.WriteRune('|')
} }
for _, e := range f.Exts { for _, p := range f.Patterns {
buf.WriteRune('*') buf.WriteString(p)
buf.WriteString(e)
buf.WriteRune(' ') buf.WriteRune(' ')
} }
res = append(res, buf.String()) res = append(res, buf.String())

View file

@ -31,7 +31,9 @@ func SelectFile(options ...Option) (string, error) {
if opts.filename != "" { if opts.filename != "" {
args.InitialDir = syscall.StringToUTF16Ptr(opts.filename) args.InitialDir = syscall.StringToUTF16Ptr(opts.filename)
} }
if opts.filters != nil {
args.Filter = &windowsFilters(opts.filters)[0] args.Filter = &windowsFilters(opts.filters)[0]
}
res := [32768]uint16{} res := [32768]uint16{}
args.File = &res[0] args.File = &res[0]
@ -59,7 +61,9 @@ func SelectFileMutiple(options ...Option) ([]string, error) {
if opts.filename != "" { if opts.filename != "" {
args.InitialDir = syscall.StringToUTF16Ptr(opts.filename) args.InitialDir = syscall.StringToUTF16Ptr(opts.filename)
} }
if opts.filters != nil {
args.Filter = &windowsFilters(opts.filters)[0] args.Filter = &windowsFilters(opts.filters)[0]
}
res := [32768 + 1024*256]uint16{} res := [32768 + 1024*256]uint16{}
args.File = &res[0] args.File = &res[0]
@ -115,7 +119,9 @@ func SelectFileSave(options ...Option) (string, error) {
if opts.overwrite { if opts.overwrite {
args.Flags |= 0x2 // OFN_OVERWRITEPROMPT args.Flags |= 0x2 // OFN_OVERWRITEPROMPT
} }
if opts.filters != nil {
args.Filter = &windowsFilters(opts.filters)[0] args.Filter = &windowsFilters(opts.filters)[0]
}
res := [32768]uint16{} res := [32768]uint16{}
args.File = &res[0] args.File = &res[0]
@ -236,9 +242,8 @@ func windowsFilters(filters []FileFilter) []uint16 {
for _, f := range filters { for _, f := range filters {
res = append(res, utf16.Encode([]rune(f.Name))...) res = append(res, utf16.Encode([]rune(f.Name))...)
res = append(res, 0) res = append(res, 0)
for _, e := range f.Exts { for _, p := range f.Patterns {
res = append(res, uint16('*')) res = append(res, utf16.Encode([]rune(p))...)
res = append(res, utf16.Encode([]rune(e))...)
res = append(res, uint16(';')) res = append(res, uint16(';'))
} }
res = append(res, 0) res = append(res, 0)

View file

@ -1,3 +1,4 @@
package cmd package cmd
var Command bool var Command bool
var Separator string

View file

@ -1 +1,3 @@
package osa package osa
//go:generate go run scripts/generate.go scripts/

View file

@ -9,8 +9,6 @@ import (
"github.com/ncruces/zenity/internal/cmd" "github.com/ncruces/zenity/internal/cmd"
) )
//go:generate go run scripts/generate.go scripts/
func Run(script string, data interface{}) ([]byte, error) { func Run(script string, data interface{}) ([]byte, error) {
var buf strings.Builder var buf strings.Builder

View file

@ -91,13 +91,12 @@ func message(typ int, text string, options []Option) (bool, error) {
func hookMessageLabels(typ int, opts options) (hook uintptr, err error) { func hookMessageLabels(typ int, opts options) (hook uintptr, err error) {
tid, _, _ := getCurrentThreadId.Call() tid, _, _ := getCurrentThreadId.Call()
hook, _, err = setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET hook, _, err = setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET
syscall.NewCallback(func(code int, wparam, lparam uintptr) uintptr { syscall.NewCallback(func(code int, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
msg := *(*_CWPRETSTRUCT)(unsafe.Pointer(lparam)) if lparam.Message == 0x0110 { // WM_INITDIALOG
if msg.Message == 0x0110 { // WM_INITDIALOG
name := [7]byte{} name := [7]byte{}
n, _, _ := getClassName.Call(msg.HWnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) n, _, _ := getClassName.Call(lparam.HWnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
if string(name[:n]) == "#32770" { if string(name[:n]) == "#32770" {
enumChildWindows.Call(msg.HWnd, enumChildWindows.Call(lparam.HWnd,
syscall.NewCallback(func(hwnd, lparam uintptr) uintptr { syscall.NewCallback(func(hwnd, lparam uintptr) uintptr {
name := [7]byte{} name := [7]byte{}
n, _, _ := getClassName.Call(hwnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) n, _, _ := getClassName.Call(hwnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name)))
@ -127,7 +126,7 @@ func hookMessageLabels(typ int, opts options) (hook uintptr, err error) {
}), 0) }), 0)
} }
} }
next, _, _ := callNextHookEx.Call(hook, uintptr(code), wparam, lparam) next, _, _ := callNextHookEx.Call(hook, uintptr(code), wparam, uintptr(unsafe.Pointer(lparam)))
return next return next
}), 0, tid) }), 0, tid)
return return

View file

@ -62,7 +62,7 @@ func ConfirmOverwrite(o *options) {
type FileFilter struct { type FileFilter struct {
Name string Name string
Exts []string Patterns []string
} }
type FileFilters []FileFilter type FileFilters []FileFilter