diff --git a/v2/internal/ffenestri/ffenestri.h b/v2/internal/ffenestri/ffenestri.h index 684b22f2e..384218975 100644 --- a/v2/internal/ffenestri/ffenestri.h +++ b/v2/internal/ffenestri/ffenestri.h @@ -29,6 +29,6 @@ extern void Fullscreen(void *app); extern void UnFullscreen(void *app); extern void ToggleFullscreen(void *app); extern void DisableFrame(void *app); -extern char *OpenDialog(void *appPointer, char *title, char *filter); +extern void OpenDialog(void *appPointer, char *callbackID, char *title, char *filter); #endif diff --git a/v2/internal/ffenestri/ffenestri_client.go b/v2/internal/ffenestri/ffenestri_client.go index 5c4de82cc..3297a491d 100644 --- a/v2/internal/ffenestri/ffenestri_client.go +++ b/v2/internal/ffenestri/ffenestri_client.go @@ -12,11 +12,7 @@ package ffenestri import "C" import ( - "encoding/json" - "fmt" - "log" "strconv" - "unsafe" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" @@ -124,27 +120,6 @@ func (c *Client) WindowSetColour(colour int) { } // OpenDialog will open a dialog with the given title and filter -func (c *Client) OpenDialog(dialogOptions *options.OpenDialog) []string { - - var result []string - - cstring := C.OpenDialog(c.app.app, c.app.string2CString(dialogOptions.Title), c.app.string2CString(dialogOptions.Filter)) - if cstring == nil { - return result - } - - jsondata := C.GoString(cstring) - // Free the C string that was allocated by the dialog - C.free(unsafe.Pointer(cstring)) - - // Unmarshal the json - err := json.Unmarshal([]byte(jsondata), &result) - if err != nil { - // ??? - log.Fatal(err) - } - - fmt.Printf("result = %+v\n", result) - - return result +func (c *Client) OpenDialog(dialogOptions *options.OpenDialog, callbackID string) { + C.OpenDialog(c.app.app, c.app.string2CString(callbackID), c.app.string2CString(dialogOptions.Title), c.app.string2CString(dialogOptions.Filter)) } diff --git a/v2/internal/ffenestri/ffenestri_darwin.c b/v2/internal/ffenestri/ffenestri_darwin.c index 6354d30c3..2224e3959 100644 --- a/v2/internal/ffenestri/ffenestri_darwin.c +++ b/v2/internal/ffenestri/ffenestri_darwin.c @@ -416,14 +416,46 @@ char* OpenFileDialog(struct Application *app, char *title, char *filter) { // OpenDialog opens a dialog to select files/directories // NOTE: The result is a string that will need to be freed! -char* OpenDialog(void *appPointer, char *title, char *filter) { - Debug("OpenDirectoryDialog Called"); - JsonNode *result = json_mkarray(); - json_append_element(result, json_mkstring("BogusDirectory 1")); - json_append_element(result, json_mkstring("BogusDirectory 2")); - char *encoded = json_stringify(result, ""); - json_delete(result); - return encoded; +void OpenDialog(struct Application *app, char* callbackID, char *title, char *filter) { + Debug("OpenDialog Called with callback id: %s", callbackID); + + // Create an open panel + ON_MAIN_THREAD( + id dialog = msg(c("NSOpenPanel"), s("openPanel")); + msg(dialog, s("setTitle:"), str(title)); + + // TODO: Filters + // No filters: [dialog setAllowsOtherFileTypes:YES]; + + // TODO: Other options + msg(dialog, s("beginSheetModalForWindow:completionHandler:"), app->mainWindow, ^(id result) { + + JsonNode *response = json_mkarray(); + + // If success + if( result == (id)1 ) { + id urls = msg(dialog, s("URLs")); + int noOfResults = (int)msg(urls, s("count")); + for( int index = 0; index < noOfResults; index++ ) { + id url = msg(urls, s("objectAtIndex:"), index); + const char *filename = (const char *)msg(msg(url, s("path")), s("UTF8String")); + json_append_element(response, json_mkstring(filename)); + } + } + + char *encoded = json_stringify(response, ""); + json_delete(response); + const char *callback = concat("D", callbackID); + const char *header = concat(callback, "|"); + const char *responseMessage = concat(header, encoded); + free((void*)callback); + free((void*)header); + app->sendMessageToBackend(responseMessage); + free(responseMessage); + }); + + msg( c("NSApp"), s("runModalForWindow:"), app->mainWindow); + ) } const char *invoke = "window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}};"; diff --git a/v2/internal/messagedispatcher/dispatchclient.go b/v2/internal/messagedispatcher/dispatchclient.go index 8dcbf692a..4894c11ab 100644 --- a/v2/internal/messagedispatcher/dispatchclient.go +++ b/v2/internal/messagedispatcher/dispatchclient.go @@ -14,7 +14,7 @@ type Client interface { Quit() NotifyEvent(message string) CallResult(message string) - OpenDialog(*options.OpenDialog) []string + OpenDialog(dialogOptions *options.OpenDialog, callbackID string) WindowSetTitle(title string) WindowShow() WindowHide() diff --git a/v2/internal/messagedispatcher/message/dialog.go b/v2/internal/messagedispatcher/message/dialog.go new file mode 100644 index 000000000..b6770a1d7 --- /dev/null +++ b/v2/internal/messagedispatcher/message/dialog.go @@ -0,0 +1,45 @@ +package message + +import ( + "encoding/json" + "fmt" + "strings" +) + +// dialogMessageParser does what it says on the tin! +func dialogMessageParser(message string) (*parsedMessage, error) { + + // Sanity check: Dialog messages must be at least 4 bytes + if len(message) < 4 { + return nil, fmt.Errorf("dialog message was an invalid length") + } + + var topic = "bad topic from dialogMessageParser" + var data []string + + // Switch the event type (with or without data) + switch message[0] { + // Format of Dialog response messages: D|<[]string as json encoded string> + case 'D': + idx := strings.IndexByte(message[1:], '|') + if idx < 0 { + return nil, fmt.Errorf("Invalid dialog response message format") + } + callbackID := message[1 : idx+1] + jsonData := message[idx+2:] + topic = "dialog:openselected:" + callbackID + + err := json.Unmarshal([]byte(jsonData), &data) + if err != nil { + return nil, err + } + + default: + return nil, fmt.Errorf("Invalid message to dialogMessageParser()") + } + + // Create a new parsed message struct + parsedMessage := &parsedMessage{Topic: topic, Data: data} + + return parsedMessage, nil +} diff --git a/v2/internal/messagedispatcher/message/event.go b/v2/internal/messagedispatcher/message/event.go index 0ce88dad5..47aa0f7d1 100644 --- a/v2/internal/messagedispatcher/message/event.go +++ b/v2/internal/messagedispatcher/message/event.go @@ -1,8 +1,9 @@ package message -import "fmt" - -import "encoding/json" +import ( + "encoding/json" + "fmt" +) type EventMessage struct { Name string `json:"name"` diff --git a/v2/internal/messagedispatcher/message/messageparser.go b/v2/internal/messagedispatcher/message/messageparser.go index 58687e42c..240a2bb2a 100644 --- a/v2/internal/messagedispatcher/message/messageparser.go +++ b/v2/internal/messagedispatcher/message/messageparser.go @@ -17,6 +17,7 @@ var messageParsers = map[byte]func(string) (*parsedMessage, error){ 'e': eventMessageParser, 'C': callMessageParser, 'W': windowMessageParser, + 'D': dialogMessageParser, } // Parse will attempt to parse the given message diff --git a/v2/internal/messagedispatcher/messagedispatcher.go b/v2/internal/messagedispatcher/messagedispatcher.go index 0c034be6e..ee1cc93d0 100644 --- a/v2/internal/messagedispatcher/messagedispatcher.go +++ b/v2/internal/messagedispatcher/messagedispatcher.go @@ -335,20 +335,14 @@ func (d *Dispatcher) processDialogMessage(result *servicebus.Message) { return } // This is hardcoded in the sender too - responseTopic := "dialog:openselected:" + splitTopic[3] - - d.logger.Info("Opening File dialog! responseTopic = %s", responseTopic) + callbackID := splitTopic[3] // TODO: Work out what we mean in a multi window environment... // For now we will just pick the first one - var result []string for _, client := range d.clients { - result = client.frontend.OpenDialog(dialogOptions) + client.frontend.OpenDialog(dialogOptions, callbackID) } - // Send dummy response - d.servicebus.Publish(responseTopic, result) - default: d.logger.Error("Unknown dialog command: %s", command) } diff --git a/v2/internal/runtime/goruntime/dialog.go b/v2/internal/runtime/goruntime/dialog.go index 1e7a74a65..e06ca056d 100644 --- a/v2/internal/runtime/goruntime/dialog.go +++ b/v2/internal/runtime/goruntime/dialog.go @@ -1,8 +1,6 @@ package goruntime import ( - b64 "encoding/base64" - "encoding/json" "fmt" "github.com/wailsapp/wails/v2/internal/crypto" @@ -68,13 +66,3 @@ func (r *dialog) Open(dialogOptions *options.OpenDialog) []string { return result.Data().([]string) } - -func optionsToBase64(dialogOptions *options.OpenDialog) (string, error) { - - encoded, err := json.Marshal(dialogOptions) - if err != nil { - return "", err - } - - return b64.StdEncoding.EncodeToString(encoded), nil -}