diff --git a/v2/internal/frontend/desktop/linux/calloc.go b/v2/internal/frontend/desktop/linux/calloc.go new file mode 100644 index 000000000..8a8158ba8 --- /dev/null +++ b/v2/internal/frontend/desktop/linux/calloc.go @@ -0,0 +1,32 @@ +package linux + +/* +#include +*/ +import "C" +import "unsafe" + +// Calloc handles alloc/dealloc of C data +type Calloc struct { + pool []unsafe.Pointer +} + +// NewCalloc creates a new allocator +func NewCalloc() Calloc { + return Calloc{} +} + +// String creates a new C string and retains a reference to it +func (c Calloc) String(in string) *C.char { + result := C.CString(in) + c.pool = append(c.pool, unsafe.Pointer(result)) + return result +} + +// Free frees all allocated C memory +func (c Calloc) Free() { + for _, str := range c.pool { + C.free(str) + } + c.pool = []unsafe.Pointer{} +} diff --git a/v2/internal/frontend/desktop/linux/dialog.go b/v2/internal/frontend/desktop/linux/dialog.go index 4e3f1e05b..7227410b4 100644 --- a/v2/internal/frontend/desktop/linux/dialog.go +++ b/v2/internal/frontend/desktop/linux/dialog.go @@ -3,10 +3,24 @@ package linux -import "github.com/wailsapp/wails/v2/internal/frontend" +import ( + "github.com/wailsapp/wails/v2/internal/frontend" +) +import "C" -func (f *Frontend) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (string, error) { - panic("implement me") +var openFileResults = make(chan string) + +func (f *Frontend) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (result string, err error) { + + f.dispatch(func() { + println("Before OpenFileDialog") + f.mainWindow.OpenFileDialog(dialogOptions) + println("After OpenFileDialog") + }) + println("Waiting for result") + result = <-openFileResults + println("Got result") + return } func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) { @@ -24,3 +38,8 @@ func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (str func (f *Frontend) MessageDialog(dialogOptions frontend.MessageDialogOptions) (string, error) { panic("implement me") } + +//export processOpenFileResult +func processOpenFileResult(result *C.char) { + openFileResults <- C.GoString(result) +} diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index abcfcd447..0161c87f3 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -24,6 +24,7 @@ import "C" import ( "context" "encoding/json" + "fmt" "log" "os" "strconv" @@ -62,6 +63,7 @@ type Frontend struct { func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { + println("[NewFrontend] PID:", os.Getpid()) // Set GDK_BACKEND=x11 to prevent warnings os.Setenv("GDK_BACKEND", "x11") @@ -301,10 +303,11 @@ var dispatchCallbackLock sync.Mutex //export callDispatchedMethod func callDispatchedMethod(cid C.int) { + println("[callDispatchedMethod] PID:", os.Getpid()) id := int(cid) fn := dispatchCallbacks[id] if fn != nil { - go fn() + fn() dispatchCallbackLock.Lock() delete(dispatchCallbacks, id) dispatchCallbackLock.Unlock() @@ -342,11 +345,24 @@ func (f *Frontend) processRequest(request unsafe.Pointer) { // Load file from asset store content, mimeType, err := f.assets.Load(file) - if err != nil { - return - } // TODO How to return 404/500 errors to webkit? + if err != nil { + if os.IsNotExist(err) { + f.dispatch(func() { + message := C.CString("not found") + defer C.free(unsafe.Pointer(message)) + C.webkit_uri_scheme_request_finish_error(req, C.g_error_new_literal(C.G_FILE_ERROR_NOENT, C.int(404), message)) + }) + } else { + err = fmt.Errorf("Error processing request %s: %w", uri, err) + f.logger.Error(err.Error()) + message := C.CString("internal server error") + defer C.free(unsafe.Pointer(message)) + C.webkit_uri_scheme_request_finish_error(req, C.g_error_new_literal(C.G_FILE_ERROR_NOENT, C.int(500), message)) + } + return + } cContent := C.CString(string(content)) defer C.free(unsafe.Pointer(cContent)) diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index 9eca7af50..11e81ff09 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -4,10 +4,11 @@ package linux /* -#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 +#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 x11 #include "gtk/gtk.h" #include "webkit2/webkit2.h" +#include #include #include @@ -105,6 +106,11 @@ ulong setupInvokeSignal(void* contentManager) { return g_signal_connect((WebKitUserContentManager*)contentManager, "script-message-received::external", G_CALLBACK(sendMessageToBackend), NULL); } +void initThreads() { + printf("init threads\n"); + XInitThreads(); +} + // These are the x,y & time of the last mouse down event // It's used for window dragging float xroot = 0.0f; @@ -199,10 +205,37 @@ int executeJS(gpointer data) { void ExecuteOnMainThread(JSCallback* jscallback) { g_idle_add((GSourceFunc)executeJS, (gpointer)jscallback); } + +void extern processOpenFileResult(char*); + +static void OpenDialog(GtkWindow* window, char *title) { + printf("Here\n"); + GtkWidget *dlg = gtk_file_chooser_dialog_new(title, window, GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL); + printf("Here3\n"); + + gint response = gtk_dialog_run(GTK_DIALOG(dlg)); + printf("Here 4\n"); + + if (response == GTK_RESPONSE_ACCEPT) + { + printf("Here 5\n"); + + gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg)); + processOpenFileResult(filename); + g_free(filename); + } + gtk_widget_destroy(dlg); +} + */ import "C" import ( + "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/pkg/options" + "os" "unsafe" ) @@ -384,6 +417,8 @@ func (w *Window) Run() { case options.Maximised: w.Maximise() } + + C.initThreads() C.gtk_main() w.Destroy() } @@ -425,3 +460,11 @@ func (w *Window) StartDrag() { func (w *Window) Quit() { C.gtk_main_quit() } + +func (w *Window) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) { + println("OpenFileDialog PID:", os.Getpid()) + mem := NewCalloc() + title := mem.String(dialogOptions.Title) + C.OpenDialog(w.asGTKWindow(), title) + mem.Free() +}