From dc5ef7f3072cac58c2ba400bf4e244b82b09ce6c Mon Sep 17 00:00:00 2001 From: Andreas Bichinger Date: Tue, 26 Mar 2024 16:06:55 +0100 Subject: [PATCH 1/4] Fix drag and drop on linux - Move C code --- v3/pkg/application/linux_cgo.c | 54 ++++++++ v3/pkg/application/linux_cgo.go | 235 ++------------------------------ v3/pkg/application/linux_cgo.h | 205 ++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 221 deletions(-) create mode 100644 v3/pkg/application/linux_cgo.c create mode 100644 v3/pkg/application/linux_cgo.h diff --git a/v3/pkg/application/linux_cgo.c b/v3/pkg/application/linux_cgo.c new file mode 100644 index 00000000000..0ecc80e401e --- /dev/null +++ b/v3/pkg/application/linux_cgo.c @@ -0,0 +1,54 @@ +#include "linux_cgo.h" + +gboolean on_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) +{ + GdkAtom target_type; + GList *targets = gdk_drag_context_list_targets(context); + + if (targets == NULL || g_list_length(targets) <= 0) + { + g_print("no targets\n"); + return FALSE; + } + /* Choose the best target type */ + target_type = GDK_POINTER_TO_ATOM(g_list_nth_data(targets, 0)); + + /* Request the data from the source. */ + gtk_drag_get_data( + widget, /* will receive 'drag-data-received' signal */ + context, /* represents the current state of the DnD */ + target_type, /* the target type we want */ + time /* time stamp */ + ); +} + +void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, + gpointer data) +{ + gint length = gtk_selection_data_get_length(selection_data); + + if (length < 0) + { + g_print("DnD failed!\n"); + gtk_drag_finish(context, FALSE, FALSE, time); + } + + gchar *uri_data = (gchar *)gtk_selection_data_get_data(selection_data); + gchar **uri_list = g_uri_list_extract_uris(uri_data); + + onUriList(uri_list, data); + + g_strfreev(uri_list); + gtk_drag_finish(context, TRUE, TRUE, time); +} + +// drag and drop tutorial: https://wiki.gnome.org/Newcomers/OldDragNDropTutorial +void enableDND(GtkWidget *widget, gpointer data) +{ + GtkTargetEntry *target = gtk_target_entry_new("text/uri-list", 0, 0); + gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT, target, 1, GDK_ACTION_COPY); + + signal_connect(widget, "drag-drop", on_drop, data); + signal_connect(widget, "drag-data-received", on_data_received, data); +} \ No newline at end of file diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index 0faff97f561..3ed5e62a271 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -17,199 +17,7 @@ import ( /* #cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 gdk-3.0 -#include -#include -#include -#include -#include -#include -#ifdef G_APPLICATION_DEFAULT_FLAGS - #define APPLICATION_DEFAULT_FLAGS G_APPLICATION_DEFAULT_FLAGS -#else - #define APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE -#endif - -typedef struct CallbackID -{ - unsigned int value; -} CallbackID; - -extern void dispatchOnMainThreadCallback(unsigned int); - -static gboolean dispatchCallback(gpointer data) { - struct CallbackID *args = data; - unsigned int cid = args->value; - dispatchOnMainThreadCallback(cid); - free(args); - - return G_SOURCE_REMOVE; -}; - -static void dispatchOnMainThread(unsigned int id) { - CallbackID *args = malloc(sizeof(CallbackID)); - args->value = id; - g_idle_add((GSourceFunc)dispatchCallback, (gpointer)args); -} - -typedef struct WindowEvent { - uint id; - uint event; -} WindowEvent; - -// exported below -void activateLinux(gpointer data); -extern void emit(WindowEvent* data); -extern gboolean handleDeleteEvent(GtkWidget*, GdkEvent*, uintptr_t); -extern gboolean handleFocusEvent(GtkWidget*, GdkEvent*, uintptr_t); -extern void handleLoadChanged(WebKitWebView*, WebKitLoadEvent, uintptr_t); -void handleClick(void*); -extern gboolean onButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); -extern gboolean onMenuButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); -extern void onDragNDrop( - void *target, - GdkDragContext* context, - gint x, - gint y, - gpointer seldata, - guint info, - guint time, - gpointer data); -extern gboolean onKeyPressEvent (GtkWidget *widget, GdkEventKey *event, uintptr_t user_data); -extern void onProcessRequest(WebKitURISchemeRequest *request, uintptr_t user_data); -extern void sendMessageToBackend(WebKitUserContentManager *contentManager, WebKitJavascriptResult *result, void *data); -// exported below (end) - -static void signal_connect(void *widget, char *event, void *cb, void* data) { - // g_signal_connect is a macro and can't be called directly - g_signal_connect(widget, event, cb, data); -} - -static WebKitWebView* webkit_web_view(GtkWidget *webview) { - return WEBKIT_WEB_VIEW(webview); -} - -static void* new_message_dialog(GtkWindow *parent, const gchar *msg, int dialogType, bool hasButtons) { - // gtk_message_dialog_new is variadic! Can't call from cgo directly - GtkWidget *dialog; - int buttonMask; - - // buttons will be added after creation - buttonMask = GTK_BUTTONS_OK; - if (hasButtons) { - buttonMask = GTK_BUTTONS_NONE; - } - - dialog = gtk_message_dialog_new( - parent, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - dialogType, - buttonMask, - "%s", - msg); - - // g_signal_connect_swapped (dialog, - // "response", - // G_CALLBACK (callback), - // dialog); - return dialog; -}; - -extern void messageDialogCB(gint button); - -static void* gtkFileChooserDialogNew(char* title, GtkWindow* window, GtkFileChooserAction action, char* cancelLabel, char* acceptLabel) { - // gtk_file_chooser_dialog_new is variadic! Can't call from cgo directly - return (GtkFileChooser*)gtk_file_chooser_dialog_new( - title, - window, - action, - cancelLabel, - GTK_RESPONSE_CANCEL, - acceptLabel, - GTK_RESPONSE_ACCEPT, - NULL); -} - -typedef struct Screen { - const char* id; - const char* name; - int p_width; - int p_height; - int width; - int height; - int x; - int y; - int w_width; - int w_height; - int w_x; - int w_y; - float scale; - double rotation; - bool isPrimary; -} Screen; - -// CREDIT: https://github.com/rainycape/magick -#include -#include -#include -#include - -static void fix_signal(int signum) { - struct sigaction st; - - if (sigaction(signum, NULL, &st) < 0) { - goto fix_signal_error; - } - st.sa_flags |= SA_ONSTACK; - if (sigaction(signum, &st, NULL) < 0) { - goto fix_signal_error; - } - return; -fix_signal_error: - fprintf(stderr, "error fixing handler for signal %d, please " - "report this issue to " - "https://github.com/wailsapp/wails: %s\n", - signum, strerror(errno)); -} - -static void install_signal_handlers() { - #if defined(SIGCHLD) - fix_signal(SIGCHLD); - #endif - #if defined(SIGHUP) - fix_signal(SIGHUP); - #endif - #if defined(SIGINT) - fix_signal(SIGINT); - #endif - #if defined(SIGQUIT) - fix_signal(SIGQUIT); - #endif - #if defined(SIGABRT) - fix_signal(SIGABRT); - #endif - #if defined(SIGFPE) - fix_signal(SIGFPE); - #endif - #if defined(SIGTERM) - fix_signal(SIGTERM); - #endif - #if defined(SIGBUS) - fix_signal(SIGBUS); - #endif - #if defined(SIGSEGV) - fix_signal(SIGSEGV); - #endif - #if defined(SIGXCPU) - fix_signal(SIGXCPU); - #endif - #if defined(SIGXFSZ) - fix_signal(SIGXFSZ); - #endif -} - -static int GetNumScreens(){ - return 0; -} +#include "linux_cgo.h" */ import "C" @@ -767,16 +575,10 @@ func (w *linuxWebviewWindow) close() { } func (w *linuxWebviewWindow) enableDND() { - id := w.parent.id - dnd := C.CString("text/uri-list") - defer C.free(unsafe.Pointer(dnd)) - targetentry := C.gtk_target_entry_new(dnd, 0, C.guint(id)) - defer C.gtk_target_entry_free(targetentry) - C.gtk_drag_dest_set((*C.GtkWidget)(w.webview), C.GTK_DEST_DEFAULT_DROP, targetentry, 1, C.GDK_ACTION_COPY) - event := C.CString("drag-data-received") - defer C.free(unsafe.Pointer(event)) - windowId := C.uint(id) - C.signal_connect(unsafe.Pointer(w.webview), event, C.onDragNDrop, unsafe.Pointer(C.gpointer(&windowId))) + C.gtk_drag_dest_unset((*C.GtkWidget)(w.webview)) + + windowId := C.uint(w.parent.id) + C.enableDND((*C.GtkWidget)(w.vbox), C.gpointer(&windowId)) } func (w *linuxWebviewWindow) execJS(js string) { @@ -1382,29 +1184,20 @@ func onMenuButtonEvent(_ *C.GtkWidget, event *C.GdkEventButton, data C.uintptr_t return C.gboolean(0) } -//export onDragNDrop -func onDragNDrop(target unsafe.Pointer, context *C.GdkDragContext, x C.gint, y C.gint, seldata unsafe.Pointer, info C.guint, time C.guint, data unsafe.Pointer) { - var length C.gint - selection := unsafe.Pointer(C.gtk_selection_data_get_data_with_length((*C.GtkSelectionData)(seldata), &length)) - extracted := C.g_uri_list_extract_uris((*C.char)(selection)) - defer C.g_strfreev(extracted) - - uris := unsafe.Slice( - (**C.char)(unsafe.Pointer(extracted)), - int(length)) - - var filenames []string - for _, uri := range uris { - if uri == nil { - break - } - filenames = append(filenames, strings.TrimPrefix(C.GoString(uri), "file://")) +//export onUriList +func onUriList(extracted **C.char, data unsafe.Pointer) { + // Credit: https://groups.google.com/g/golang-nuts/c/bI17Bpck8K4/m/DVDa7EMtDAAJ + offset := unsafe.Sizeof(uintptr(0)) + filenames := []string{} + for *extracted != nil { + filenames = append(filenames, strings.TrimPrefix(C.GoString(*extracted), "file://")) + extracted = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(extracted)) + offset)) } + windowDragAndDropBuffer <- &dragAndDropMessage{ windowId: uint(*((*C.uint)(data))), filenames: filenames, } - C.gtk_drag_finish(context, C.true, C.false, time) } //export onKeyPressEvent diff --git a/v3/pkg/application/linux_cgo.h b/v3/pkg/application/linux_cgo.h new file mode 100644 index 00000000000..0577fd27c24 --- /dev/null +++ b/v3/pkg/application/linux_cgo.h @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include +#include +#ifdef G_APPLICATION_DEFAULT_FLAGS +#define APPLICATION_DEFAULT_FLAGS G_APPLICATION_DEFAULT_FLAGS +#else +#define APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE +#endif + +typedef struct CallbackID +{ + unsigned int value; +} CallbackID; + +extern void dispatchOnMainThreadCallback(unsigned int); + +static gboolean dispatchCallback(gpointer data) +{ + struct CallbackID *args = data; + unsigned int cid = args->value; + dispatchOnMainThreadCallback(cid); + free(args); + + return G_SOURCE_REMOVE; +}; + +static void dispatchOnMainThread(unsigned int id) +{ + CallbackID *args = malloc(sizeof(CallbackID)); + args->value = id; + g_idle_add((GSourceFunc)dispatchCallback, (gpointer)args); +} + +typedef struct WindowEvent +{ + uint id; + uint event; +} WindowEvent; + +// exported below +void activateLinux(gpointer data); +extern void emit(WindowEvent *data); +extern gboolean handleDeleteEvent(GtkWidget *, GdkEvent *, uintptr_t); +extern gboolean handleFocusEvent(GtkWidget *, GdkEvent *, uintptr_t); +extern void handleLoadChanged(WebKitWebView *, WebKitLoadEvent, uintptr_t); +void handleClick(void *); +extern gboolean onButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); +extern gboolean onMenuButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); +extern void onUriList(char **extracted, gpointer data); +extern gboolean onKeyPressEvent(GtkWidget *widget, GdkEventKey *event, uintptr_t user_data); +extern void onProcessRequest(WebKitURISchemeRequest *request, uintptr_t user_data); +extern void sendMessageToBackend(WebKitUserContentManager *contentManager, WebKitJavascriptResult *result, void *data); +// exported below (end) + +static void signal_connect(void *widget, char *event, void *cb, void *data) +{ + // g_signal_connect is a macro and can't be called directly + g_signal_connect(widget, event, cb, data); +} + +static WebKitWebView *webkit_web_view(GtkWidget *webview) +{ + return WEBKIT_WEB_VIEW(webview); +} + +static void *new_message_dialog(GtkWindow *parent, const gchar *msg, int dialogType, bool hasButtons) +{ + // gtk_message_dialog_new is variadic! Can't call from cgo directly + GtkWidget *dialog; + int buttonMask; + + // buttons will be added after creation + buttonMask = GTK_BUTTONS_OK; + if (hasButtons) + { + buttonMask = GTK_BUTTONS_NONE; + } + + dialog = gtk_message_dialog_new( + parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + dialogType, + buttonMask, + "%s", + msg); + + // g_signal_connect_swapped (dialog, + // "response", + // G_CALLBACK (callback), + // dialog); + return dialog; +}; + +extern void messageDialogCB(gint button); + +static void *gtkFileChooserDialogNew(char *title, GtkWindow *window, GtkFileChooserAction action, char *cancelLabel, char *acceptLabel) +{ + // gtk_file_chooser_dialog_new is variadic! Can't call from cgo directly + return (GtkFileChooser *)gtk_file_chooser_dialog_new( + title, + window, + action, + cancelLabel, + GTK_RESPONSE_CANCEL, + acceptLabel, + GTK_RESPONSE_ACCEPT, + NULL); +} + +typedef struct Screen +{ + const char *id; + const char *name; + int p_width; + int p_height; + int width; + int height; + int x; + int y; + int w_width; + int w_height; + int w_x; + int w_y; + float scale; + double rotation; + bool isPrimary; +} Screen; + +// CREDIT: https://github.com/rainycape/magick +#include +#include +#include +#include + +static void fix_signal(int signum) +{ + struct sigaction st; + + if (sigaction(signum, NULL, &st) < 0) + { + goto fix_signal_error; + } + st.sa_flags |= SA_ONSTACK; + if (sigaction(signum, &st, NULL) < 0) + { + goto fix_signal_error; + } + return; +fix_signal_error: + fprintf(stderr, "error fixing handler for signal %d, please " + "report this issue to " + "https://github.com/wailsapp/wails: %s\n", + signum, strerror(errno)); +} + +static void install_signal_handlers() +{ +#if defined(SIGCHLD) + fix_signal(SIGCHLD); +#endif +#if defined(SIGHUP) + fix_signal(SIGHUP); +#endif +#if defined(SIGINT) + fix_signal(SIGINT); +#endif +#if defined(SIGQUIT) + fix_signal(SIGQUIT); +#endif +#if defined(SIGABRT) + fix_signal(SIGABRT); +#endif +#if defined(SIGFPE) + fix_signal(SIGFPE); +#endif +#if defined(SIGTERM) + fix_signal(SIGTERM); +#endif +#if defined(SIGBUS) + fix_signal(SIGBUS); +#endif +#if defined(SIGSEGV) + fix_signal(SIGSEGV); +#endif +#if defined(SIGXCPU) + fix_signal(SIGXCPU); +#endif +#if defined(SIGXFSZ) + fix_signal(SIGXFSZ); +#endif +} + +static int GetNumScreens() +{ + return 0; +} + +gboolean on_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data); +void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, + gpointer data); +void enableDND(GtkWidget *widget, gpointer data); \ No newline at end of file From fdbd07c33115f6d99712603d97bf01ca54d13b9b Mon Sep 17 00:00:00 2001 From: Andreas Bichinger Date: Tue, 26 Mar 2024 16:21:14 +0100 Subject: [PATCH 2/4] Use GTK_DEST_DEFAULT_DROP --- v3/pkg/application/linux_cgo.c | 25 +------------------------ v3/pkg/application/linux_cgo.h | 1 - 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/v3/pkg/application/linux_cgo.c b/v3/pkg/application/linux_cgo.c index 0ecc80e401e..e202de43158 100644 --- a/v3/pkg/application/linux_cgo.c +++ b/v3/pkg/application/linux_cgo.c @@ -1,27 +1,5 @@ #include "linux_cgo.h" -gboolean on_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) -{ - GdkAtom target_type; - GList *targets = gdk_drag_context_list_targets(context); - - if (targets == NULL || g_list_length(targets) <= 0) - { - g_print("no targets\n"); - return FALSE; - } - /* Choose the best target type */ - target_type = GDK_POINTER_TO_ATOM(g_list_nth_data(targets, 0)); - - /* Request the data from the source. */ - gtk_drag_get_data( - widget, /* will receive 'drag-data-received' signal */ - context, /* represents the current state of the DnD */ - target_type, /* the target type we want */ - time /* time stamp */ - ); -} - void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, gpointer data) @@ -47,8 +25,7 @@ void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y void enableDND(GtkWidget *widget, gpointer data) { GtkTargetEntry *target = gtk_target_entry_new("text/uri-list", 0, 0); - gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT, target, 1, GDK_ACTION_COPY); + gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target, 1, GDK_ACTION_COPY); - signal_connect(widget, "drag-drop", on_drop, data); signal_connect(widget, "drag-data-received", on_data_received, data); } \ No newline at end of file diff --git a/v3/pkg/application/linux_cgo.h b/v3/pkg/application/linux_cgo.h index 0577fd27c24..c77c9730aaa 100644 --- a/v3/pkg/application/linux_cgo.h +++ b/v3/pkg/application/linux_cgo.h @@ -198,7 +198,6 @@ static int GetNumScreens() return 0; } -gboolean on_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data); void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint time, gpointer data); From 77fd3409ffc62be23a8368e95e50475f4f3c46fa Mon Sep 17 00:00:00 2001 From: Andreas Bichinger Date: Tue, 26 Mar 2024 16:52:41 +0100 Subject: [PATCH 3/4] Update changelog --- mkdocs-website/docs/en/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs-website/docs/en/changelog.md b/mkdocs-website/docs/en/changelog.md index 85b9f894b7b..6d82b20c6b4 100644 --- a/mkdocs-website/docs/en/changelog.md +++ b/mkdocs-website/docs/en/changelog.md @@ -57,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix custom context menu closing immediately on linux by [@abichinger](https://github.com/abichinger) in [#3330](https://github.com/wailsapp/wails/pull/3330) - Fix the output path and extension of model files produced by the binding generator by [@fbbdev](https://github.com/fbbdev) in [#3334](https://github.com/wailsapp/wails/pull/3334) - Fix the import paths of model files in JS code produced by the binding generator by [@fbbdev](https://github.com/fbbdev) in [#3334](https://github.com/wailsapp/wails/pull/3334) +- Fix drag-n-drop on some linux distros by [@abichinger](https://github.com/abichinger) in [#3346](https://github.com/wailsapp/wails/pull/3346) ### Changed From 031aefd203445a4f486a2643d53eb61ae8183370 Mon Sep 17 00:00:00 2001 From: Andreas Bichinger Date: Wed, 10 Apr 2024 16:21:41 +0200 Subject: [PATCH 4/4] Move C code back into `linux_cgo.go` --- v3/pkg/application/linux_cgo.c | 31 ----- v3/pkg/application/linux_cgo.go | 216 +++++++++++++++++++++++++++++++- v3/pkg/application/linux_cgo.h | 204 ------------------------------ 3 files changed, 215 insertions(+), 236 deletions(-) delete mode 100644 v3/pkg/application/linux_cgo.c delete mode 100644 v3/pkg/application/linux_cgo.h diff --git a/v3/pkg/application/linux_cgo.c b/v3/pkg/application/linux_cgo.c deleted file mode 100644 index e202de43158..00000000000 --- a/v3/pkg/application/linux_cgo.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "linux_cgo.h" - -void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, - GtkSelectionData *selection_data, guint target_type, guint time, - gpointer data) -{ - gint length = gtk_selection_data_get_length(selection_data); - - if (length < 0) - { - g_print("DnD failed!\n"); - gtk_drag_finish(context, FALSE, FALSE, time); - } - - gchar *uri_data = (gchar *)gtk_selection_data_get_data(selection_data); - gchar **uri_list = g_uri_list_extract_uris(uri_data); - - onUriList(uri_list, data); - - g_strfreev(uri_list); - gtk_drag_finish(context, TRUE, TRUE, time); -} - -// drag and drop tutorial: https://wiki.gnome.org/Newcomers/OldDragNDropTutorial -void enableDND(GtkWidget *widget, gpointer data) -{ - GtkTargetEntry *target = gtk_target_entry_new("text/uri-list", 0, 0); - gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target, 1, GDK_ACTION_COPY); - - signal_connect(widget, "drag-data-received", on_data_received, data); -} \ No newline at end of file diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index 3ed5e62a271..9696070da9b 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -17,7 +17,221 @@ import ( /* #cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 gdk-3.0 -#include "linux_cgo.h" +#include +#include +#include +#include +#include +#include +#ifdef G_APPLICATION_DEFAULT_FLAGS + #define APPLICATION_DEFAULT_FLAGS G_APPLICATION_DEFAULT_FLAGS +#else + #define APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE +#endif + +typedef struct CallbackID +{ + unsigned int value; +} CallbackID; + +extern void dispatchOnMainThreadCallback(unsigned int); + +static gboolean dispatchCallback(gpointer data) { + struct CallbackID *args = data; + unsigned int cid = args->value; + dispatchOnMainThreadCallback(cid); + free(args); + + return G_SOURCE_REMOVE; +}; + +static void dispatchOnMainThread(unsigned int id) { + CallbackID *args = malloc(sizeof(CallbackID)); + args->value = id; + g_idle_add((GSourceFunc)dispatchCallback, (gpointer)args); +} + +typedef struct WindowEvent { + uint id; + uint event; +} WindowEvent; + +// exported below +void activateLinux(gpointer data); +extern void emit(WindowEvent* data); +extern gboolean handleDeleteEvent(GtkWidget*, GdkEvent*, uintptr_t); +extern gboolean handleFocusEvent(GtkWidget*, GdkEvent*, uintptr_t); +extern void handleLoadChanged(WebKitWebView*, WebKitLoadEvent, uintptr_t); +void handleClick(void*); +extern gboolean onButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); +extern gboolean onMenuButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); +extern void onUriList(char **extracted, gpointer data); +extern gboolean onKeyPressEvent (GtkWidget *widget, GdkEventKey *event, uintptr_t user_data); +extern void onProcessRequest(WebKitURISchemeRequest *request, uintptr_t user_data); +extern void sendMessageToBackend(WebKitUserContentManager *contentManager, WebKitJavascriptResult *result, void *data); +// exported below (end) + +static void signal_connect(void *widget, char *event, void *cb, void* data) { + // g_signal_connect is a macro and can't be called directly + g_signal_connect(widget, event, cb, data); +} + +static WebKitWebView* webkit_web_view(GtkWidget *webview) { + return WEBKIT_WEB_VIEW(webview); +} + +static void* new_message_dialog(GtkWindow *parent, const gchar *msg, int dialogType, bool hasButtons) { + // gtk_message_dialog_new is variadic! Can't call from cgo directly + GtkWidget *dialog; + int buttonMask; + + // buttons will be added after creation + buttonMask = GTK_BUTTONS_OK; + if (hasButtons) { + buttonMask = GTK_BUTTONS_NONE; + } + + dialog = gtk_message_dialog_new( + parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + dialogType, + buttonMask, + "%s", + msg); + + // g_signal_connect_swapped (dialog, + // "response", + // G_CALLBACK (callback), + // dialog); + return dialog; +}; + +extern void messageDialogCB(gint button); + +static void* gtkFileChooserDialogNew(char* title, GtkWindow* window, GtkFileChooserAction action, char* cancelLabel, char* acceptLabel) { + // gtk_file_chooser_dialog_new is variadic! Can't call from cgo directly + return (GtkFileChooser*)gtk_file_chooser_dialog_new( + title, + window, + action, + cancelLabel, + GTK_RESPONSE_CANCEL, + acceptLabel, + GTK_RESPONSE_ACCEPT, + NULL); +} + +typedef struct Screen { + const char* id; + const char* name; + int p_width; + int p_height; + int width; + int height; + int x; + int y; + int w_width; + int w_height; + int w_x; + int w_y; + float scale; + double rotation; + bool isPrimary; +} Screen; + +// CREDIT: https://github.com/rainycape/magick +#include +#include +#include +#include + +static void fix_signal(int signum) { + struct sigaction st; + + if (sigaction(signum, NULL, &st) < 0) { + goto fix_signal_error; + } + st.sa_flags |= SA_ONSTACK; + if (sigaction(signum, &st, NULL) < 0) { + goto fix_signal_error; + } + return; +fix_signal_error: + fprintf(stderr, "error fixing handler for signal %d, please " + "report this issue to " + "https://github.com/wailsapp/wails: %s\n", + signum, strerror(errno)); +} + +static void install_signal_handlers() { + #if defined(SIGCHLD) + fix_signal(SIGCHLD); + #endif + #if defined(SIGHUP) + fix_signal(SIGHUP); + #endif + #if defined(SIGINT) + fix_signal(SIGINT); + #endif + #if defined(SIGQUIT) + fix_signal(SIGQUIT); + #endif + #if defined(SIGABRT) + fix_signal(SIGABRT); + #endif + #if defined(SIGFPE) + fix_signal(SIGFPE); + #endif + #if defined(SIGTERM) + fix_signal(SIGTERM); + #endif + #if defined(SIGBUS) + fix_signal(SIGBUS); + #endif + #if defined(SIGSEGV) + fix_signal(SIGSEGV); + #endif + #if defined(SIGXCPU) + fix_signal(SIGXCPU); + #endif + #if defined(SIGXFSZ) + fix_signal(SIGXFSZ); + #endif +} + +static int GetNumScreens(){ + return 0; +} + +static void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *selection_data, guint target_type, guint time, + gpointer data) +{ + gint length = gtk_selection_data_get_length(selection_data); + + if (length < 0) + { + g_print("DnD failed!\n"); + gtk_drag_finish(context, FALSE, FALSE, time); + } + + gchar *uri_data = (gchar *)gtk_selection_data_get_data(selection_data); + gchar **uri_list = g_uri_list_extract_uris(uri_data); + + onUriList(uri_list, data); + + g_strfreev(uri_list); + gtk_drag_finish(context, TRUE, TRUE, time); +} + +// drag and drop tutorial: https://wiki.gnome.org/Newcomers/OldDragNDropTutorial +static void enableDND(GtkWidget *widget, gpointer data) +{ + GtkTargetEntry *target = gtk_target_entry_new("text/uri-list", 0, 0); + gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target, 1, GDK_ACTION_COPY); + + signal_connect(widget, "drag-data-received", on_data_received, data); +} */ import "C" diff --git a/v3/pkg/application/linux_cgo.h b/v3/pkg/application/linux_cgo.h deleted file mode 100644 index c77c9730aaa..00000000000 --- a/v3/pkg/application/linux_cgo.h +++ /dev/null @@ -1,204 +0,0 @@ -#include -#include -#include -#include -#include -#include -#ifdef G_APPLICATION_DEFAULT_FLAGS -#define APPLICATION_DEFAULT_FLAGS G_APPLICATION_DEFAULT_FLAGS -#else -#define APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE -#endif - -typedef struct CallbackID -{ - unsigned int value; -} CallbackID; - -extern void dispatchOnMainThreadCallback(unsigned int); - -static gboolean dispatchCallback(gpointer data) -{ - struct CallbackID *args = data; - unsigned int cid = args->value; - dispatchOnMainThreadCallback(cid); - free(args); - - return G_SOURCE_REMOVE; -}; - -static void dispatchOnMainThread(unsigned int id) -{ - CallbackID *args = malloc(sizeof(CallbackID)); - args->value = id; - g_idle_add((GSourceFunc)dispatchCallback, (gpointer)args); -} - -typedef struct WindowEvent -{ - uint id; - uint event; -} WindowEvent; - -// exported below -void activateLinux(gpointer data); -extern void emit(WindowEvent *data); -extern gboolean handleDeleteEvent(GtkWidget *, GdkEvent *, uintptr_t); -extern gboolean handleFocusEvent(GtkWidget *, GdkEvent *, uintptr_t); -extern void handleLoadChanged(WebKitWebView *, WebKitLoadEvent, uintptr_t); -void handleClick(void *); -extern gboolean onButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); -extern gboolean onMenuButtonEvent(GtkWidget *widget, GdkEventButton *event, uintptr_t user_data); -extern void onUriList(char **extracted, gpointer data); -extern gboolean onKeyPressEvent(GtkWidget *widget, GdkEventKey *event, uintptr_t user_data); -extern void onProcessRequest(WebKitURISchemeRequest *request, uintptr_t user_data); -extern void sendMessageToBackend(WebKitUserContentManager *contentManager, WebKitJavascriptResult *result, void *data); -// exported below (end) - -static void signal_connect(void *widget, char *event, void *cb, void *data) -{ - // g_signal_connect is a macro and can't be called directly - g_signal_connect(widget, event, cb, data); -} - -static WebKitWebView *webkit_web_view(GtkWidget *webview) -{ - return WEBKIT_WEB_VIEW(webview); -} - -static void *new_message_dialog(GtkWindow *parent, const gchar *msg, int dialogType, bool hasButtons) -{ - // gtk_message_dialog_new is variadic! Can't call from cgo directly - GtkWidget *dialog; - int buttonMask; - - // buttons will be added after creation - buttonMask = GTK_BUTTONS_OK; - if (hasButtons) - { - buttonMask = GTK_BUTTONS_NONE; - } - - dialog = gtk_message_dialog_new( - parent, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - dialogType, - buttonMask, - "%s", - msg); - - // g_signal_connect_swapped (dialog, - // "response", - // G_CALLBACK (callback), - // dialog); - return dialog; -}; - -extern void messageDialogCB(gint button); - -static void *gtkFileChooserDialogNew(char *title, GtkWindow *window, GtkFileChooserAction action, char *cancelLabel, char *acceptLabel) -{ - // gtk_file_chooser_dialog_new is variadic! Can't call from cgo directly - return (GtkFileChooser *)gtk_file_chooser_dialog_new( - title, - window, - action, - cancelLabel, - GTK_RESPONSE_CANCEL, - acceptLabel, - GTK_RESPONSE_ACCEPT, - NULL); -} - -typedef struct Screen -{ - const char *id; - const char *name; - int p_width; - int p_height; - int width; - int height; - int x; - int y; - int w_width; - int w_height; - int w_x; - int w_y; - float scale; - double rotation; - bool isPrimary; -} Screen; - -// CREDIT: https://github.com/rainycape/magick -#include -#include -#include -#include - -static void fix_signal(int signum) -{ - struct sigaction st; - - if (sigaction(signum, NULL, &st) < 0) - { - goto fix_signal_error; - } - st.sa_flags |= SA_ONSTACK; - if (sigaction(signum, &st, NULL) < 0) - { - goto fix_signal_error; - } - return; -fix_signal_error: - fprintf(stderr, "error fixing handler for signal %d, please " - "report this issue to " - "https://github.com/wailsapp/wails: %s\n", - signum, strerror(errno)); -} - -static void install_signal_handlers() -{ -#if defined(SIGCHLD) - fix_signal(SIGCHLD); -#endif -#if defined(SIGHUP) - fix_signal(SIGHUP); -#endif -#if defined(SIGINT) - fix_signal(SIGINT); -#endif -#if defined(SIGQUIT) - fix_signal(SIGQUIT); -#endif -#if defined(SIGABRT) - fix_signal(SIGABRT); -#endif -#if defined(SIGFPE) - fix_signal(SIGFPE); -#endif -#if defined(SIGTERM) - fix_signal(SIGTERM); -#endif -#if defined(SIGBUS) - fix_signal(SIGBUS); -#endif -#if defined(SIGSEGV) - fix_signal(SIGSEGV); -#endif -#if defined(SIGXCPU) - fix_signal(SIGXCPU); -#endif -#if defined(SIGXFSZ) - fix_signal(SIGXFSZ); -#endif -} - -static int GetNumScreens() -{ - return 0; -} - -void on_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, - GtkSelectionData *selection_data, guint target_type, guint time, - gpointer data); -void enableDND(GtkWidget *widget, gpointer data); \ No newline at end of file