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
*.syso

View File

@ -11,6 +11,8 @@ import (
"github.com/ncruces/zenity/internal/cmd"
)
//go:generate go run github.com/josephspurrier/goversioninfo/cmd/goversioninfo -platform-specific -manifest=win.manifest
var (
// Application Options
errorDlg bool
@ -58,6 +60,18 @@ func main() {
msgResult(zenity.Warning(text, opts...))
case questionDlg:
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()
@ -95,7 +109,7 @@ func setupFlags() {
flag.BoolVar(&directory, "directory", false, "Activate directory-only selection")
flag.BoolVar(&confirmOverwrite, "confirm-overwrite", false, "Confirm file selection if filename already exists")
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 ...)")
}
@ -157,6 +171,16 @@ func loadFlags() []zenity.Option {
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
}
@ -177,8 +201,36 @@ func msgResult(ok bool, err error) {
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 {
list []zenity.FileFilter
zenity.FileFilters
}
func (f *FileFilters) String() string {
@ -193,8 +245,8 @@ func (f *FileFilters) Set(s string) error {
s = split[1]
}
filter.Exts = strings.Split(s, " ")
f.list = append(f.list, filter)
filter.Patterns = strings.Split(s, " ")
f.FileFilters = append(f.FileFilters, filter)
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 {
var filter []string
for _, f := range filters {
for _, e := range f.Exts {
filter = append(filter, strings.TrimPrefix(e, "."))
for _, p := range f.Patterns {
filter = append(filter, p) // FIXME
}
}
return filter

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,8 +9,6 @@ import (
"github.com/ncruces/zenity/internal/cmd"
)
//go:generate go run scripts/generate.go scripts/
func Run(script string, data interface{}) ([]byte, error) {
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) {
tid, _, _ := getCurrentThreadId.Call()
hook, _, err = setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET
syscall.NewCallback(func(code int, wparam, lparam uintptr) uintptr {
msg := *(*_CWPRETSTRUCT)(unsafe.Pointer(lparam))
if msg.Message == 0x0110 { // WM_INITDIALOG
syscall.NewCallback(func(code int, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr {
if lparam.Message == 0x0110 { // WM_INITDIALOG
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" {
enumChildWindows.Call(msg.HWnd,
enumChildWindows.Call(lparam.HWnd,
syscall.NewCallback(func(hwnd, lparam uintptr) uintptr {
name := [7]byte{}
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)
}
}
next, _, _ := callNextHookEx.Call(hook, uintptr(code), wparam, lparam)
next, _, _ := callNextHookEx.Call(hook, uintptr(code), wparam, uintptr(unsafe.Pointer(lparam)))
return next
}), 0, tid)
return

View File

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