diff --git a/cmd/zenity/main.go b/cmd/zenity/main.go index b56049b..d7eb84d 100644 --- a/cmd/zenity/main.go +++ b/cmd/zenity/main.go @@ -3,6 +3,9 @@ package main import ( "flag" "os" + "os/exec" + "path/filepath" + "runtime" "strings" "github.com/ncruces/zenity" @@ -42,6 +45,10 @@ var ( filename string separator string fileFilters FileFilters + + // Windows specific options + cygpath bool + wslpath bool ) func main() { @@ -64,11 +71,11 @@ func main() { case fileSelectionDlg: switch { default: - strResult(zenity.SelectFile(opts...)) + strResult(egestPath(zenity.SelectFile(opts...))) case save: - strResult(zenity.SelectFileSave(opts...)) + strResult(egestPath(zenity.SelectFileSave(opts...))) case multiple: - lstResult(zenity.SelectFileMutiple(opts...)) + lstResult(egestPaths(zenity.SelectFileMutiple(opts...))) } } @@ -111,6 +118,12 @@ func setupFlags() { flag.StringVar(&filename, "filename", "", "Set the filename") flag.StringVar(&separator, "separator", "|", "Set output separator character") flag.Var(&fileFilters, "file-filter", "Set a filename filter (NAME | PATTERN1 PATTERN2 ...)") + + // Windows specific options + if runtime.GOOS == "windows" { + flag.BoolVar(&cygpath, "cygpath", false, "Use cygpath for path translation (Windows only)") + flag.BoolVar(&wslpath, "wslpath", false, "Use wslpath for path translation (Windows only)") + } } func validateFlags() { @@ -174,7 +187,7 @@ func loadFlags() []zenity.Option { // File selection options options = append(options, fileFilters.Build()) - options = append(options, zenity.Filename(filename)) + options = append(options, zenity.Filename(ingestPath(filename))) if directory { options = append(options, zenity.Directory()) } @@ -238,12 +251,66 @@ func lstResult(l []string, err error) { os.Exit(0) } +func ingestPath(path string) string { + if runtime.GOOS == "windows" && path != "" { + var args []string + switch { + case wslpath: + args = []string{"wsl", "wslpath", "-m"} + case cygpath: + args = []string{"cygpath", "-C", "UTF8", "-m"} + } + if args != nil { + args = append(args, path) + out, err := exec.Command(args[0], args[1:]...).Output() + if len(out) > 0 && err == nil { + path = string(out[:len(out)-1]) + } + } + } + return path +} + +func egestPath(path string, err error) (string, error) { + if runtime.GOOS == "windows" && path != "" && err == nil { + var args []string + switch { + case wslpath: + args = []string{"wsl", "wslpath", "-u"} + case cygpath: + args = []string{"cygpath", "-C", "UTF8", "-u"} + } + if args != nil { + var out []byte + args = append(args, filepath.ToSlash(path)) + out, err = exec.Command(args[0], args[1:]...).Output() + if len(out) > 0 && err == nil { + path = string(out[:len(out)-1]) + } + } + } + return path, err +} + +func egestPaths(paths []string, err error) ([]string, error) { + if runtime.GOOS == "windows" && err == nil && (wslpath || cygpath) { + paths = append(paths[:0:0], paths...) + for i, p := range paths { + paths[i], err = egestPath(p, nil) + if err != nil { + break + } + } + } + return paths, err +} + type FileFilters struct { zenity.FileFilters } func (f *FileFilters) String() string { - return "filename filter" + return "zenity.FileFilters" } func (f *FileFilters) Set(s string) error { diff --git a/file_windows.go b/file_windows.go index 25a406f..7b0d069 100644 --- a/file_windows.go +++ b/file_windows.go @@ -275,9 +275,9 @@ func browseForFolder(opts options) (string, []string, error) { if opts.filename != "" { ptr := syscall.StringToUTF16Ptr(opts.filename) args.LParam = uintptr(unsafe.Pointer(ptr)) - args.CallbackFunc = syscall.NewCallback(func(hwnd uintptr, msg uint32, lparam, data uintptr) uintptr { + args.CallbackFunc = syscall.NewCallback(func(wnd uintptr, msg uint32, lparam, data uintptr) uintptr { if msg == 1 { // BFFM_INITIALIZED - sendMessage.Call(hwnd, 1024+103 /* BFFM_SETSELECTIONW */, 1 /* TRUE */, data) + sendMessage.Call(wnd, 1024+103 /* BFFM_SETSELECTIONW */, 1 /* TRUE */, data) } return 0 }) diff --git a/msg_test.go b/msg_test.go index 0498c67..d7bc350 100644 --- a/msg_test.go +++ b/msg_test.go @@ -3,7 +3,7 @@ package zenity_test import "github.com/ncruces/zenity" func ExampleError() { - zenity.Error("An error has occured.", + zenity.Error("An error has occurred.", zenity.Title("Error"), zenity.Icon(zenity.ErrorIcon)) // Output: diff --git a/msg_windows.go b/msg_windows.go index d9bf9d4..9586c34 100644 --- a/msg_windows.go +++ b/msg_windows.go @@ -93,15 +93,15 @@ func hookMessageLabels(typ int, opts options) (hook uintptr, err error) { hook, _, err = setWindowsHookEx.Call(12, // WH_CALLWNDPROCRET syscall.NewCallback(func(code int, wparam uintptr, lparam *_CWPRETSTRUCT) uintptr { if lparam.Message == 0x0110 { // WM_INITDIALOG - name := [7]byte{} - n, _, _ := getClassName.Call(lparam.HWnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) - if string(name[:n]) == "#32770" { - 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))) - if string(name[:n]) == "Button" { - ctl, _, _ := getDlgCtrlID.Call(hwnd) + name := [7]uint16{} + getClassName.Call(lparam.Wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) + if syscall.UTF16ToString(name[:]) == "#32770" { // The class for a dialog box + enumChildWindows.Call(lparam.Wnd, + syscall.NewCallback(func(wnd, lparam uintptr) uintptr { + name := [7]uint16{} + getClassName.Call(wnd, uintptr(unsafe.Pointer(&name)), uintptr(len(name))) + if syscall.UTF16ToString(name[:]) == "Button" { + ctl, _, _ := getDlgCtrlID.Call(wnd) var text string switch ctl { case 1, 6: // IDOK, IDYES @@ -119,7 +119,7 @@ func hookMessageLabels(typ int, opts options) (hook uintptr, err error) { } if text != "" { ptr := syscall.StringToUTF16Ptr(text) - setWindowText.Call(hwnd, uintptr(unsafe.Pointer(ptr))) + setWindowText.Call(wnd, uintptr(unsafe.Pointer(ptr))) } } return 1 diff --git a/init_windows.go b/util_windows.go similarity index 96% rename from init_windows.go rename to util_windows.go index 433c729..d24d292 100644 --- a/init_windows.go +++ b/util_windows.go @@ -23,7 +23,7 @@ var ( coTaskMemFree = ole32.NewProc("CoTaskMemFree") sendMessage = user32.NewProc("SendMessageW") - getClassName = user32.NewProc("GetClassNameA") + getClassName = user32.NewProc("GetClassNameW") setWindowsHookEx = user32.NewProc("SetWindowsHookExW") unhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx") callNextHookEx = user32.NewProc("CallNextHookEx") @@ -46,7 +46,7 @@ type _CWPRETSTRUCT struct { LParam uintptr WParam uintptr Message uint32 - HWnd uintptr + Wnd uintptr } type _COMObject struct{} diff --git a/init_windows_test.go b/util_windows_test.go similarity index 100% rename from init_windows_test.go rename to util_windows_test.go