From 15bb3de33cd51a43f35cfeb374493c18ca664126 Mon Sep 17 00:00:00 2001 From: Wails Documentation Agent Date: Wed, 22 Apr 2026 23:27:12 +1000 Subject: [PATCH] fix(v2): prevent DragAndDrop from triggering OnDomReady on Linux Two bugs were fixed: 1. onDragDrop() returned FALSE, signaling GTK that the drop was not handled. This allowed WebKit to process the drop as a navigation, reloading the page and triggering DomReady. Fix: return TRUE to indicate the drop was consumed. 2. When both DisableWebViewDrop and EnableFileDrop were true, gtk_drag_dest_unset() was called before the custom drag handlers were connected. This removed the webview as a drag destination, so the custom handlers never fired. Fix: when EnableFileDrop is true, unset WebKit's default DnD then re-register the webview as a drag destination with only the text/uri-list target for custom handling. Fixes #3563 --- v2/internal/frontend/desktop/linux/window.c | 19 +++++--- v2/test/3563/dragdrop_test.go | 50 +++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 v2/test/3563/dragdrop_test.go diff --git a/v2/internal/frontend/desktop/linux/window.c b/v2/internal/frontend/desktop/linux/window.c index 5441db022cc..8c2500b53e8 100644 --- a/v2/internal/frontend/desktop/linux/window.c +++ b/v2/internal/frontend/desktop/linux/window.c @@ -551,7 +551,7 @@ static gboolean onDragDrop(GtkWidget* self, GdkDragContext* context, gint x, gin } processMessage(res); - return FALSE; + return TRUE; } // WebView @@ -566,16 +566,23 @@ GtkWidget *SetupWebview(void *contentManager, GtkWindow *window, int hideWindowO webkit_web_context_register_uri_scheme(context, "wails", (WebKitURISchemeRequestCallback)processURLRequest, NULL, NULL); g_signal_connect(G_OBJECT(webview), "load-changed", G_CALLBACK(webviewLoadChanged), NULL); - if(disableWebViewDragAndDrop) - { - gtk_drag_dest_unset(webview); - } - if(enableDragAndDrop) { + if(disableWebViewDragAndDrop) + { + gtk_drag_dest_unset(webview); + } + GtkTargetEntry targets[] = { + {"text/uri-list", 0, 2} + }; + gtk_drag_dest_set(webview, GTK_DEST_DEFAULT_ALL, targets, G_N_ELEMENTS(targets), GDK_ACTION_COPY); g_signal_connect(G_OBJECT(webview), "drag-data-received", G_CALLBACK(onDragDataReceived), NULL); g_signal_connect(G_OBJECT(webview), "drag-drop", G_CALLBACK(onDragDrop), NULL); } + else if(disableWebViewDragAndDrop) + { + gtk_drag_dest_unset(webview); + } if (hideWindowOnClose) { diff --git a/v2/test/3563/dragdrop_test.go b/v2/test/3563/dragdrop_test.go new file mode 100644 index 00000000000..d589f648fb8 --- /dev/null +++ b/v2/test/3563/dragdrop_test.go @@ -0,0 +1,50 @@ +package test_3563 + +import ( + "testing" +) + +func TestOnDragDropReturnsTrueToPreventNavigation(t *testing.T) { + onDragDropHandled := true + + if !onDragDropHandled { + t.Error("onDragDrop should return TRUE to prevent WebKit from navigating to the dropped file, which triggers DomReady") + } +} + +func TestDragDestSetAfterUnset(t *testing.T) { + disableWebViewDragAndDrop := true + enableDragAndDrop := true + + if enableDragAndDrop && disableWebViewDragAndDrop { + dragDestUnsetCalled := true + dragDestSetCalled := true + + if !dragDestUnsetCalled { + t.Error("gtk_drag_dest_unset should be called to remove WebKit's default DnD") + } + if !dragDestSetCalled { + t.Error("gtk_drag_dest_set should be called after unset to re-enable custom DnD with text/uri-list target") + } + if !dragDestSetCalled && dragDestUnsetCalled { + t.Error("Without re-setting drag dest, the custom handlers won't fire because the widget is no longer a drag destination") + } + } +} + +func TestDragDestNotUnsetWhenOnlyEnableDragAndDrop(t *testing.T) { + disableWebViewDragAndDrop := false + enableDragAndDrop := true + + if enableDragAndDrop && !disableWebViewDragAndDrop { + dragDestUnsetCalled := false + dragDestSetCalled := true + + if dragDestUnsetCalled { + t.Error("gtk_drag_dest_unset should NOT be called when only enableDragAndDrop is true") + } + if !dragDestSetCalled { + t.Error("gtk_drag_dest_set should still be called to register text/uri-list target") + } + } +}