5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 07:21:32 +08:00

[v2, windows] Make sure to open the CommonFileDialogs on the main thread (#2606)

Otherwise it might have some strange side-effects like blocking
the completion of Deferrals in WebView2 when using custom
IStreams.
This commit is contained in:
stffabi 2023-04-17 12:50:27 +02:00 committed by GitHub
parent 46bcce7566
commit 767bfcff89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 54 deletions

View File

@ -4,13 +4,14 @@
package windows package windows
import ( import (
"path/filepath"
"strings"
"syscall"
"github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend"
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32"
"github.com/wailsapp/wails/v2/internal/go-common-file-dialog/cfd" "github.com/wailsapp/wails/v2/internal/go-common-file-dialog/cfd"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"path/filepath"
"strings"
"syscall"
) )
func (f *Frontend) getHandleForDialog() w32.HWND { func (f *Frontend) getHandleForDialog() w32.HWND {
@ -40,27 +41,20 @@ func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (stri
Role: "PickFolder", Role: "PickFolder",
Folder: defaultFolder, Folder: defaultFolder,
} }
thisDialog, err := cfd.NewSelectFolderDialog(config)
if err != nil { result, err := f.showCfdDialog(
return "", err func() (cfd.Dialog, error) {
} return cfd.NewSelectFolderDialog(config)
thisDialog.SetParentWindowHandle(f.getHandleForDialog()) }, false)
defer func(thisDialog cfd.SelectFolderDialog) {
err := thisDialog.Release()
if err != nil {
println("ERROR: Unable to release dialog:", err.Error())
}
}(thisDialog)
result, err := thisDialog.ShowAndGetResult()
if err != nil && err != cfd.ErrorCancelled { if err != nil && err != cfd.ErrorCancelled {
return "", err return "", err
} }
return result, nil return result.(string), nil
} }
// OpenFileDialog prompts the user to select a file // OpenFileDialog prompts the user to select a file
func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) { func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) {
defaultFolder, err := getDefaultFolder(options.DefaultDirectory) defaultFolder, err := getDefaultFolder(options.DefaultDirectory)
if err != nil { if err != nil {
return "", err return "", err
@ -72,22 +66,16 @@ func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, e
FileName: options.DefaultFilename, FileName: options.DefaultFilename,
Title: options.Title, Title: options.Title,
} }
thisdialog, err := cfd.NewOpenFileDialog(config)
if err != nil { result, err := f.showCfdDialog(
return "", err func() (cfd.Dialog, error) {
} return cfd.NewOpenFileDialog(config)
thisdialog.SetParentWindowHandle(f.getHandleForDialog()) }, false)
defer func(thisdialog cfd.OpenFileDialog) {
err := thisdialog.Release()
if err != nil {
println("ERROR: Unable to release dialog:", err.Error())
}
}(thisdialog)
result, err := thisdialog.ShowAndGetResult()
if err != nil && err != cfd.ErrorCancelled { if err != nil && err != cfd.ErrorCancelled {
return "", err return "", err
} }
return result, nil return result.(string), nil
} }
// OpenMultipleFilesDialog prompts the user to select a file // OpenMultipleFilesDialog prompts the user to select a file
@ -105,22 +93,16 @@ func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) (
FileName: options.DefaultFilename, FileName: options.DefaultFilename,
Folder: defaultFolder, Folder: defaultFolder,
} }
thisdialog, err := cfd.NewOpenMultipleFilesDialog(config)
if err != nil { result, err := f.showCfdDialog(
return nil, err func() (cfd.Dialog, error) {
} return cfd.NewOpenMultipleFilesDialog(config)
thisdialog.SetParentWindowHandle(f.getHandleForDialog()) }, true)
defer func(thisdialog cfd.OpenMultipleFilesDialog) {
err := thisdialog.Release()
if err != nil {
println("ERROR: Unable to release dialog:", err.Error())
}
}(thisdialog)
result, err := thisdialog.ShowAndGetResults()
if err != nil && err != cfd.ErrorCancelled { if err != nil && err != cfd.ErrorCancelled {
return nil, err return nil, err
} }
return result, nil return result.([]string), nil
} }
// SaveFileDialog prompts the user to select a file // SaveFileDialog prompts the user to select a file
@ -131,26 +113,44 @@ func (f *Frontend) SaveFileDialog(options frontend.SaveDialogOptions) (string, e
return "", err return "", err
} }
saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{ config := cfd.DialogConfig{
Title: options.Title, Title: options.Title,
Role: "SaveFile", Role: "SaveFile",
FileFilters: convertFilters(options.Filters), FileFilters: convertFilters(options.Filters),
FileName: options.DefaultFilename, FileName: options.DefaultFilename,
Folder: defaultFolder, Folder: defaultFolder,
})
if err != nil {
return "", err
} }
saveDialog.SetParentWindowHandle(f.getHandleForDialog())
err = saveDialog.Show() result, err := f.showCfdDialog(
if err != nil { func() (cfd.Dialog, error) {
return "", err return cfd.NewSaveFileDialog(config)
} }, false)
result, err := saveDialog.GetResult()
if err != nil && err != cfd.ErrorCancelled { if err != nil && err != cfd.ErrorCancelled {
return "", err 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 { func calculateMessageDialogFlags(options frontend.MessageDialogOptions) uint32 {

View File

@ -3,6 +3,7 @@
package windows package windows
import ( import (
"sync"
"unsafe" "unsafe"
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/go-webview2/pkg/edge" "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() 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
}

View File

@ -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 `-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 `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) - 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 ## v2.4.1 - 2023-03-20