diff --git a/v2/internal/frontend/desktop/linux/gtk.go b/v2/internal/frontend/desktop/linux/gtk.go index 1592ccdc7..ead303539 100644 --- a/v2/internal/frontend/desktop/linux/gtk.go +++ b/v2/internal/frontend/desktop/linux/gtk.go @@ -11,8 +11,11 @@ extern void blockClick(GtkWidget* menuItem, gulong handler_id); extern void unblockClick(GtkWidget* menuItem, gulong handler_id); */ import "C" -import "unsafe" -import "github.com/wailsapp/wails/v2/pkg/menu" +import ( + "unsafe" + + "github.com/wailsapp/wails/v2/pkg/menu" +) func GtkMenuItemWithLabel(label string) *C.GtkWidget { cLabel := C.CString(label) @@ -37,6 +40,10 @@ func GtkRadioMenuItemWithLabel(label string, group *C.GSList) *C.GtkWidget { //export handleMenuItemClick func handleMenuItemClick(gtkWidget unsafe.Pointer) { + // Make sure to execute the final callback on a new goroutine otherwise if the callback e.g. tries to open a dialog, the + // main thread will get blocked and so the message loop blocks. As a result the app will block and shows a + // "not responding" dialog. + item := gtkSignalToMenuItem[(*C.GtkWidget)(gtkWidget)] switch item.Type { case menu.CheckboxType: @@ -51,7 +58,7 @@ func handleMenuItemClick(gtkWidget unsafe.Pointer) { C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(gtkCheckbox)), checked) C.unblockClick(gtkCheckbox, handler) } - item.Click(&menu.CallbackData{MenuItem: item}) + go item.Click(&menu.CallbackData{MenuItem: item}) case menu.RadioType: gtkRadioItems := gtkRadioMenuCache[item] active := C.gtk_check_menu_item_get_active(C.toGtkCheckMenuItem(gtkWidget)) @@ -63,11 +70,11 @@ func handleMenuItemClick(gtkWidget unsafe.Pointer) { C.unblockClick(gtkRadioItem, handler) } item.Checked = true - item.Click(&menu.CallbackData{MenuItem: item}) + go item.Click(&menu.CallbackData{MenuItem: item}) } else { item.Checked = false } default: - item.Click(&menu.CallbackData{MenuItem: item}) + go item.Click(&menu.CallbackData{MenuItem: item}) } } diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index 7c6b6f363..888faddaf 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -314,7 +314,7 @@ gboolean messageDialog(gpointer data) { void extern processOpenFileResult(void*); typedef struct OpenFileDialogOptions { - void* webview; + GtkWindow* window; char* title; char* defaultFilename; char* defaultDirectory; @@ -339,7 +339,7 @@ gboolean opendialog(gpointer data) { if (options->action == GTK_FILE_CHOOSER_ACTION_SAVE) { label = "_Save"; } - GtkWidget *dlgWidget = gtk_file_chooser_dialog_new(options->title, options->webview, options->action, + GtkWidget *dlgWidget = gtk_file_chooser_dialog_new(options->title, options->window, options->action, "_Cancel", GTK_RESPONSE_CANCEL, label, GTK_RESPONSE_ACCEPT, NULL); @@ -854,7 +854,7 @@ func (w *Window) Quit() { func (w *Window) OpenFileDialog(dialogOptions frontend.OpenDialogOptions, multipleFiles int, action C.GtkFileChooserAction) { data := C.OpenFileDialogOptions{ - webview: w.webview, + window: w.asGTKWindow(), title: C.CString(dialogOptions.Title), multipleFiles: C.int(multipleFiles), action: action,