diff --git a/v2/internal/frontend/desktop/windows/dialog.go b/v2/internal/frontend/desktop/windows/dialog.go index ab41df332..1ca422b71 100644 --- a/v2/internal/frontend/desktop/windows/dialog.go +++ b/v2/internal/frontend/desktop/windows/dialog.go @@ -4,13 +4,14 @@ package windows import ( + "path/filepath" + "strings" + "syscall" + "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" "github.com/wailsapp/wails/v2/internal/go-common-file-dialog/cfd" "golang.org/x/sys/windows" - "path/filepath" - "strings" - "syscall" ) func (f *Frontend) getHandleForDialog() w32.HWND { @@ -40,27 +41,20 @@ func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (stri Role: "PickFolder", Folder: defaultFolder, } - thisDialog, err := cfd.NewSelectFolderDialog(config) - if err != nil { - return "", err - } - thisDialog.SetParentWindowHandle(f.getHandleForDialog()) - defer func(thisDialog cfd.SelectFolderDialog) { - err := thisDialog.Release() - if err != nil { - println("ERROR: Unable to release dialog:", err.Error()) - } - }(thisDialog) - result, err := thisDialog.ShowAndGetResult() + + result, err := f.showCfdDialog( + func() (cfd.Dialog, error) { + return cfd.NewSelectFolderDialog(config) + }, false) + if err != nil && err != cfd.ErrorCancelled { return "", err } - return result, nil + return result.(string), nil } // OpenFileDialog prompts the user to select a file func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) { - defaultFolder, err := getDefaultFolder(options.DefaultDirectory) if err != nil { return "", err @@ -72,22 +66,16 @@ func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, e FileName: options.DefaultFilename, Title: options.Title, } - thisdialog, err := cfd.NewOpenFileDialog(config) - if err != nil { - return "", err - } - thisdialog.SetParentWindowHandle(f.getHandleForDialog()) - defer func(thisdialog cfd.OpenFileDialog) { - err := thisdialog.Release() - if err != nil { - println("ERROR: Unable to release dialog:", err.Error()) - } - }(thisdialog) - result, err := thisdialog.ShowAndGetResult() + + result, err := f.showCfdDialog( + func() (cfd.Dialog, error) { + return cfd.NewOpenFileDialog(config) + }, false) + if err != nil && err != cfd.ErrorCancelled { return "", err } - return result, nil + return result.(string), nil } // OpenMultipleFilesDialog prompts the user to select a file @@ -105,22 +93,16 @@ func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ( FileName: options.DefaultFilename, Folder: defaultFolder, } - thisdialog, err := cfd.NewOpenMultipleFilesDialog(config) - if err != nil { - return nil, err - } - thisdialog.SetParentWindowHandle(f.getHandleForDialog()) - defer func(thisdialog cfd.OpenMultipleFilesDialog) { - err := thisdialog.Release() - if err != nil { - println("ERROR: Unable to release dialog:", err.Error()) - } - }(thisdialog) - result, err := thisdialog.ShowAndGetResults() + + result, err := f.showCfdDialog( + func() (cfd.Dialog, error) { + return cfd.NewOpenMultipleFilesDialog(config) + }, true) + if err != nil && err != cfd.ErrorCancelled { return nil, err } - return result, nil + return result.([]string), nil } // SaveFileDialog prompts the user to select a file @@ -131,26 +113,44 @@ func (f *Frontend) SaveFileDialog(options frontend.SaveDialogOptions) (string, e return "", err } - saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{ + config := cfd.DialogConfig{ Title: options.Title, Role: "SaveFile", FileFilters: convertFilters(options.Filters), FileName: options.DefaultFilename, Folder: defaultFolder, - }) - if err != nil { - return "", err } - saveDialog.SetParentWindowHandle(f.getHandleForDialog()) - err = saveDialog.Show() - if err != nil { - return "", err - } - result, err := saveDialog.GetResult() + + result, err := f.showCfdDialog( + func() (cfd.Dialog, error) { + return cfd.NewSaveFileDialog(config) + }, false) + if err != nil && err != cfd.ErrorCancelled { return "", err } - return result, nil + return result.(string), nil +} + +func (f *Frontend) showCfdDialog(newDlg func() (cfd.Dialog, error), isMultiSelect bool) (any, error) { + return invokeSync(f.mainWindow, func() (any, error) { + dlg, err := newDlg() + if err != nil { + return nil, err + } + defer func() { + err := dlg.Release() + if err != nil { + println("ERROR: Unable to release dialog:", err.Error()) + } + }() + + dlg.SetParentWindowHandle(f.getHandleForDialog()) + if multi, _ := dlg.(cfd.OpenMultipleFilesDialog); multi != nil && isMultiSelect { + return multi.ShowAndGetResults() + } + return dlg.ShowAndGetResult() + }) } func calculateMessageDialogFlags(options frontend.MessageDialogOptions) uint32 { diff --git a/v2/internal/frontend/desktop/windows/window.go b/v2/internal/frontend/desktop/windows/window.go index 9080009a9..43ec57c72 100644 --- a/v2/internal/frontend/desktop/windows/window.go +++ b/v2/internal/frontend/desktop/windows/window.go @@ -3,6 +3,7 @@ package windows import ( + "sync" "unsafe" "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/go-webview2/pkg/edge" @@ -323,3 +324,14 @@ func (w *Window) SetTheme(theme winoptions.Theme) { w.UpdateTheme() }) } + +func invokeSync[T any](cba *Window, fn func() (T, error)) (res T, err error) { + var wg sync.WaitGroup + wg.Add(1) + cba.Invoke(func() { + res, err = fn() + wg.Done() + }) + wg.Wait() + return res, err +} diff --git a/website/src/pages/changelog.mdx b/website/src/pages/changelog.mdx index 54f5344fe..0a0ab8359 100644 --- a/website/src/pages/changelog.mdx +++ b/website/src/pages/changelog.mdx @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed `-skipbindings` flag in `wails dev`. Fixed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2584) - Fixed `runtime.MenuUpdateApplicationMenu` on macOS. Fixed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2588) - Fixed add package name for `libwebkit`/`pkg-config` and use shell.RunCommandWithENV instead of shell.RunCommand in `zypper.go`. Fixed by @wgjtyu in [PR](https://github.com/wailsapp/wails/pull/2593) +- Make sure to start the CommonFileDialogs on Windows on the Main-Thread. Fixed by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2606) ## v2.4.1 - 2023-03-20