From 757a4383e677ee2becba23fdfc4a8358dcd7e4c7 Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Fri, 29 Sep 2023 23:54:57 -0500 Subject: [PATCH] [v3] send dialog results over channels --- v3/pkg/application/dialogs.go | 32 +++++++++++++---- v3/pkg/application/dialogs_darwin.go | 38 ++++++++++----------- v3/pkg/application/dialogs_linux.go | 4 +-- v3/pkg/application/dialogs_windows.go | 23 ++++++++++--- v3/pkg/application/linux_cgo.go | 49 ++++++++++++++------------- 5 files changed, 88 insertions(+), 58 deletions(-) diff --git a/v3/pkg/application/dialogs.go b/v3/pkg/application/dialogs.go index dfc9c9227..bd54059f3 100644 --- a/v3/pkg/application/dialogs.go +++ b/v3/pkg/application/dialogs.go @@ -1,6 +1,7 @@ package application import ( + "fmt" "strings" "sync" ) @@ -159,7 +160,7 @@ func (d *MessageDialog) SetMessage(message string) *MessageDialog { } type openFileDialogImpl interface { - show() ([]string, error) + show() (chan string, error) } type FileFilter struct { @@ -265,10 +266,11 @@ func (d *OpenFileDialogStruct) PromptForSingleSelection() (string, error) { if d.impl == nil { d.impl = newOpenFileDialogImpl(d) } - selection, err := InvokeSyncWithResultAndError(d.impl.show) + var result string - if len(selection) > 0 { - result = selection[0] + selections, err := InvokeSyncWithResultAndError(d.impl.show) + if err == nil { + result = <-selections } return result, err @@ -289,7 +291,17 @@ func (d *OpenFileDialogStruct) PromptForMultipleSelection() ([]string, error) { if d.impl == nil { d.impl = newOpenFileDialogImpl(d) } - return InvokeSyncWithResultAndError(d.impl.show) + + selections, err := InvokeSyncWithResultAndError(d.impl.show) + + var result []string + fmt.Println("Waiting for results:") + for filename := range selections { + fmt.Println(filename) + result = append(result, filename) + } + + return result, err } func (d *OpenFileDialogStruct) SetMessage(message string) *OpenFileDialogStruct { @@ -385,7 +397,7 @@ type SaveFileDialogStruct struct { } type saveFileDialogImpl interface { - show() (string, error) + show() (chan string, error) } func (d *SaveFileDialogStruct) SetOptions(options *SaveFileDialogOptions) { @@ -448,7 +460,13 @@ func (d *SaveFileDialogStruct) PromptForSingleSelection() (string, error) { if d.impl == nil { d.impl = newSaveFileDialogImpl(d) } - return InvokeSyncWithResultAndError(d.impl.show) + + var result string + selections, err := InvokeSyncWithResultAndError(d.impl.show) + if err == nil { + result = <-selections + } + return result, err } func (d *SaveFileDialogStruct) SetButtonText(text string) *SaveFileDialogStruct { diff --git a/v3/pkg/application/dialogs_darwin.go b/v3/pkg/application/dialogs_darwin.go index b3753092b..bdd7aa289 100644 --- a/v3/pkg/application/dialogs_darwin.go +++ b/v3/pkg/application/dialogs_darwin.go @@ -18,7 +18,7 @@ extern void saveFileDialogCallback(uint id, char* path); static void showAboutBox(char* title, char *message, void *icon, int length) { // run on main thread - dispatch_async(dispatch_get_main_queue(), ^{ + // dispatch_async(dispatch_get_main_queue(), ^{ NSAlert *alert = [[NSAlert alloc] init]; if (title != NULL) { [alert setMessageText:[NSString stringWithUTF8String:title]]; @@ -34,7 +34,7 @@ static void showAboutBox(char* title, char *message, void *icon, int length) { } [alert setAlertStyle:NSAlertStyleInformational]; [alert runModal]; - }); + // }); } @@ -163,7 +163,7 @@ static void showOpenFileDialog(unsigned int dialogID, void *window) { // run on main thread - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ NSOpenPanel *panel = [NSOpenPanel openPanel]; @@ -229,7 +229,7 @@ static void showOpenFileDialog(unsigned int dialogID, processOpenFileDialogResults(panel, result, dialogID); }]; } - }); + }); } static void showSaveFileDialog(unsigned int dialogID, @@ -246,7 +246,7 @@ static void showSaveFileDialog(unsigned int dialogID, void *window) { // run on main thread - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ NSSavePanel *panel = [NSSavePanel savePanel]; if (message != NULL) { @@ -280,8 +280,8 @@ static void showSaveFileDialog(unsigned int dialogID, [panel beginSheetModalForWindow:(__bridge NSWindow *)window completionHandler:^(NSInteger result) { const char *path = NULL; if (result == NSModalResponseOK) { - NSURL *url = [panel URL]; - const char *path = [[url path] UTF8String]; + NSURL *url = [panel URL]; + path = [[url path] UTF8String]; } saveFileDialogCallback(dialogID, (char *)path); }]; @@ -290,12 +290,12 @@ static void showSaveFileDialog(unsigned int dialogID, const char *path = NULL; if (result == NSModalResponseOK) { NSURL *url = [panel URL]; - const char *path = [[url path] UTF8String]; + path = [[url path] UTF8String]; } saveFileDialogCallback(dialogID, (char *)path); }]; } - }); + }); } */ @@ -321,7 +321,9 @@ func (m *macosApp) showAboutDialog(title string, message string, icon []byte) { if icon != nil { iconData = unsafe.Pointer(&icon[0]) } - C.showAboutBox(C.CString(title), C.CString(message), iconData, C.int(len(icon))) + InvokeAsync(func() { + C.showAboutBox(C.CString(title), C.CString(message), iconData, C.int(len(icon))) + }) } type macosDialog struct { @@ -331,7 +333,7 @@ type macosDialog struct { } func (m *macosDialog) show() { - globalApplication.dispatchOnMainThread(func() { + InvokeAsync(func() { // Mac can only have 4 Buttons on a dialog if len(m.dialog.Buttons) > 4 { @@ -419,7 +421,7 @@ func toCString(s string) *C.char { return C.CString(s) } -func (m *macosOpenFileDialog) show() ([]string, error) { +func (m *macosOpenFileDialog) show() (chan string, error) { openFileResponses[m.dialog.id] = make(chan string) nsWindow := unsafe.Pointer(nil) if m.dialog.window != nil { @@ -445,7 +447,6 @@ func (m *macosOpenFileDialog) show() ([]string, error) { } filterPatterns = strings.Join(allPatterns, ";") } - C.showOpenFileDialog(C.uint(m.dialog.id), C.bool(m.dialog.canChooseFiles), C.bool(m.dialog.canChooseDirectories), @@ -462,11 +463,8 @@ func (m *macosOpenFileDialog) show() ([]string, error) { toCString(m.dialog.directory), toCString(m.dialog.buttonText), nsWindow) - var result []string - for filename := range openFileResponses[m.dialog.id] { - result = append(result, filename) - } - return result, nil + + return openFileResponses[m.dialog.id], nil } //export openFileDialogCallback @@ -504,7 +502,7 @@ func newSaveFileDialogImpl(d *SaveFileDialogStruct) *macosSaveFileDialog { } } -func (m *macosSaveFileDialog) show() (string, error) { +func (m *macosSaveFileDialog) show() (chan string, error) { saveFileResponses[m.dialog.id] = make(chan string) nsWindow := unsafe.Pointer(nil) if m.dialog.window != nil { @@ -524,7 +522,7 @@ func (m *macosSaveFileDialog) show() (string, error) { toCString(m.dialog.buttonText), toCString(m.dialog.filename), nsWindow) - return <-saveFileResponses[m.dialog.id], nil + return saveFileResponses[m.dialog.id], nil } //export saveFileDialogCallback diff --git a/v3/pkg/application/dialogs_linux.go b/v3/pkg/application/dialogs_linux.go index b64734549..4943766f0 100644 --- a/v3/pkg/application/dialogs_linux.go +++ b/v3/pkg/application/dialogs_linux.go @@ -53,7 +53,7 @@ func newOpenFileDialogImpl(d *OpenFileDialogStruct) *linuxOpenFileDialog { } } -func (m *linuxOpenFileDialog) show() ([]string, error) { +func (m *linuxOpenFileDialog) show() (chan string, error) { return runOpenFileDialog(m.dialog) } @@ -67,6 +67,6 @@ func newSaveFileDialogImpl(d *SaveFileDialogStruct) *linuxSaveFileDialog { } } -func (m *linuxSaveFileDialog) show() (string, error) { +func (m *linuxSaveFileDialog) show() (chan string, error) { return runSaveFileDialog(m.dialog) } diff --git a/v3/pkg/application/dialogs_windows.go b/v3/pkg/application/dialogs_windows.go index 93baf6a76..f77167545 100644 --- a/v3/pkg/application/dialogs_windows.go +++ b/v3/pkg/application/dialogs_windows.go @@ -91,7 +91,7 @@ func getDefaultFolder(folder string) (string, error) { return filepath.Abs(folder) } -func (m *windowOpenFileDialog) show() ([]string, error) { +func (m *windowOpenFileDialog) show() (chan string, error) { defaultFolder, err := getDefaultFolder(m.dialog.directory) if err != nil { @@ -133,7 +133,14 @@ func (m *windowOpenFileDialog) show() ([]string, error) { result = []string{temp.(string)} } - return result, nil + files := make(chan string) + go func() { + for _, file := range result { + files <- file + } + close(files) + }() + return files, nil } type windowSaveFileDialog struct { @@ -146,10 +153,12 @@ func newSaveFileDialogImpl(d *SaveFileDialogStruct) *windowSaveFileDialog { } } -func (m *windowSaveFileDialog) show() (string, error) { +func (m *windowSaveFileDialog) show() (chan string, error) { + files := make(chan string) defaultFolder, err := getDefaultFolder(m.dialog.directory) if err != nil { - return "", err + close(files) + return files, err } config := cfd.DialogConfig{ @@ -164,7 +173,11 @@ func (m *windowSaveFileDialog) show() (string, error) { func() (cfd.Dialog, error) { return cfd.NewSaveFileDialog(config) }, false) - return result.(string), nil + go func() { + files <- result.(string) + close(files) + }() + return files, err } func calculateMessageDialogFlags(options MessageDialogOptions) uint32 { diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index 65838ae5e..dcdffaae8 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -973,7 +973,7 @@ func messageDialogCB(button C.int) { } -func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden bool, currentFolder, title string, action int, acceptLabel string, filters []FileFilter) ([]string, error) { +func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden bool, currentFolder, title string, action int, acceptLabel string, filters []FileFilter) (chan string, error) { titleStr := C.CString(title) defer C.free(unsafe.Pointer(titleStr)) cancelStr := C.CString("_Cancel") @@ -1036,27 +1036,32 @@ func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden b return string(bytes) } - response := C.gtk_dialog_run((*C.GtkDialog)(fc)) - selections := []string{} - if response == C.GTK_RESPONSE_ACCEPT { - filenames := C.gtk_file_chooser_get_filenames((*C.GtkFileChooser)(fc)) - iter := filenames - count := 0 - for { - selections = append(selections, buildStringAndFree(C.gpointer(iter.data))) - iter = iter.next - if iter == nil || count == 1024 { - break + selections := make(chan string) + // run this on the gtk thread + InvokeAsync(func() { + go func() { + response := C.gtk_dialog_run((*C.GtkDialog)(fc)) + if response == C.GTK_RESPONSE_ACCEPT { + filenames := C.gtk_file_chooser_get_filenames((*C.GtkFileChooser)(fc)) + iter := filenames + count := 0 + for { + selections <- buildStringAndFree(C.gpointer(iter.data)) + iter = iter.next + if iter == nil || count == 1024 { + break + } + count++ + } + close(selections) + C.gtk_widget_destroy((*C.GtkWidget)(unsafe.Pointer(fc))) } - count++ - } - } - - defer C.gtk_widget_destroy((*C.GtkWidget)(unsafe.Pointer(fc))) + }() + }) return selections, nil } -func runOpenFileDialog(dialog *OpenFileDialogStruct) ([]string, error) { +func runOpenFileDialog(dialog *OpenFileDialogStruct) (chan string, error) { const GtkFileChooserActionOpen = C.GTK_FILE_CHOOSER_ACTION_OPEN window := nilPointer @@ -1145,7 +1150,7 @@ func runQuestionDialog(parent pointer, options *MessageDialog) int { return int(C.gtk_dialog_run((*C.GtkDialog)(unsafe.Pointer(dialog)))) } -func runSaveFileDialog(dialog *SaveFileDialogStruct) (string, error) { +func runSaveFileDialog(dialog *SaveFileDialogStruct) (chan string, error) { window := nilPointer buttonText := dialog.buttonText if buttonText == "" { @@ -1162,11 +1167,7 @@ func runSaveFileDialog(dialog *SaveFileDialogStruct) (string, error) { buttonText, dialog.filters) - if err != nil || len(results) == 0 { - return "", err - } - - return results[0], nil + return results, err } // systray