WIP: zenity command (windows).
This commit is contained in:
parent
7f608be6c2
commit
1fc55eed81
13 changed files with 141 additions and 34 deletions
1
cmd/zenity/.gitignore
vendored
1
cmd/zenity/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
zenity
|
||||
*.syso
|
|
@ -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
|
||||
}
|
||||
|
|
41
cmd/zenity/versioninfo.json
Normal file
41
cmd/zenity/versioninfo.json
Normal 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
9
cmd/zenity/win.manifest
Normal 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>
|
|
@ -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
|
||||
|
|
18
file_test.go
18
file_test.go
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
package cmd
|
||||
|
||||
var Command bool
|
||||
var Separator string
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
package osa
|
||||
|
||||
//go:generate go run scripts/generate.go scripts/
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -61,8 +61,8 @@ func ConfirmOverwrite(o *options) {
|
|||
}
|
||||
|
||||
type FileFilter struct {
|
||||
Name string
|
||||
Exts []string
|
||||
Name string
|
||||
Patterns []string
|
||||
}
|
||||
|
||||
type FileFilters []FileFilter
|
||||
|
|
Loading…
Reference in a new issue