| /* |
| * Copyright (C) 2020 Igalia S.L. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "DragSource.h" |
| |
| #if ENABLE(DRAG_SUPPORT) && USE(GTK4) |
| |
| #include "WebKitWebViewBasePrivate.h" |
| #include <WebCore/GtkUtilities.h> |
| #include <gtk/gtk.h> |
| |
| namespace WebKit { |
| using namespace WebCore; |
| |
| DragSource::DragSource(GtkWidget* webView) |
| : m_webView(webView) |
| { |
| } |
| |
| DragSource::~DragSource() |
| { |
| } |
| |
| void DragSource::begin(SelectionData&& selectionData, OptionSet<DragOperation> operationMask, RefPtr<ShareableBitmap>&& image) |
| { |
| if (m_drag) { |
| gdk_drag_drop_done(m_drag.get(), FALSE); |
| m_drag = nullptr; |
| } |
| |
| m_selectionData = WTFMove(selectionData); |
| |
| Vector<GdkContentProvider*> providers; |
| if (m_selectionData->hasMarkup()) { |
| CString markup = m_selectionData->markup().utf8(); |
| GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new(markup.data(), markup.length())); |
| providers.append(gdk_content_provider_new_for_bytes("text/html", bytes.get())); |
| } |
| |
| if (m_selectionData->hasURIList()) { |
| CString uriList = m_selectionData->uriList().utf8(); |
| GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new(uriList.data(), uriList.length())); |
| providers.append(gdk_content_provider_new_for_bytes("text/uri-list", bytes.get())); |
| } |
| |
| if (m_selectionData->hasURL()) { |
| CString urlString = m_selectionData->url().string().utf8(); |
| gchar* url = g_strdup_printf("%s\n%s", urlString.data(), m_selectionData->hasText() ? m_selectionData->text().utf8().data() : urlString.data()); |
| GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new_take(url, strlen(url))); |
| providers.append(gdk_content_provider_new_for_bytes("_NETSCAPE_URL", bytes.get())); |
| } |
| |
| if (m_selectionData->hasImage()) { |
| GRefPtr<GdkPixbuf> pixbuf = adoptGRef(m_selectionData->image()->getGdkPixbuf()); |
| providers.append(gdk_content_provider_new_typed(GDK_TYPE_PIXBUF, pixbuf.get())); |
| } |
| |
| if (m_selectionData->hasText()) |
| providers.append(gdk_content_provider_new_typed(G_TYPE_STRING, m_selectionData->text().utf8().data())); |
| |
| if (m_selectionData->canSmartReplace()) { |
| GRefPtr<GBytes> bytes = adoptGRef(g_bytes_new(nullptr, 0)); |
| providers.append(gdk_content_provider_new_for_bytes("application/vnd.webkitgtk.smartpaste", bytes.get())); |
| } |
| |
| auto* surface = gtk_native_get_surface(gtk_widget_get_native(m_webView)); |
| auto* device = gdk_seat_get_pointer(gdk_display_get_default_seat(gtk_widget_get_display(m_webView))); |
| GRefPtr<GdkContentProvider> provider = adoptGRef(gdk_content_provider_new_union(providers.data(), providers.size())); |
| m_drag = adoptGRef(gdk_drag_begin(surface, device, provider.get(), dragOperationToGdkDragActions(operationMask), 0, 0)); |
| g_signal_connect(m_drag.get(), "dnd-finished", G_CALLBACK(+[](GdkDrag* gtkDrag, gpointer userData) { |
| auto& drag = *static_cast<DragSource*>(userData); |
| if (drag.m_drag.get() != gtkDrag) |
| return; |
| |
| drag.m_selectionData = WTF::nullopt; |
| drag.m_drag = nullptr; |
| |
| GdkDevice* device = gdk_drag_get_device(gtkDrag); |
| double x = 0; |
| double y = 0; |
| gdk_device_get_surface_at_position(device, &x, &y); |
| |
| auto* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(drag.m_webView)); |
| ASSERT(page); |
| |
| IntPoint point(x, y); |
| page->dragEnded(point, point, gdkDragActionToDragOperation(gdk_drag_get_selected_action(gtkDrag))); |
| }), this); |
| |
| g_signal_connect(m_drag.get(), "cancel", G_CALLBACK(+[](GdkDrag* gtkDrag, GdkDragCancelReason, gpointer userData) { |
| auto& drag = *static_cast<DragSource*>(userData); |
| if (drag.m_drag.get() != gtkDrag) |
| return; |
| |
| drag.m_selectionData = WTF::nullopt; |
| drag.m_drag = nullptr; |
| }), this); |
| |
| auto* dragIcon = gtk_drag_icon_get_for_drag(m_drag.get()); |
| RefPtr<Image> iconImage = image ? image->createImage() : nullptr; |
| if (iconImage) { |
| if (GRefPtr<GdkTexture> texture = adoptGRef(iconImage->gdkTexture())) { |
| gdk_drag_set_hotspot(m_drag.get(), -gdk_texture_get_width(texture.get()) / 2, -gdk_texture_get_height(texture.get()) / 2); |
| auto* picture = gtk_picture_new_for_paintable(GDK_PAINTABLE(texture.get())); |
| gtk_drag_icon_set_child(GTK_DRAG_ICON(dragIcon), picture); |
| return; |
| } |
| } |
| |
| gdk_drag_set_hotspot(m_drag.get(), -2, -2); |
| auto* child = gtk_image_new_from_icon_name("text-x-generic"); |
| gtk_image_set_icon_size(GTK_IMAGE(child), GTK_ICON_SIZE_LARGE); |
| gtk_drag_icon_set_child(GTK_DRAG_ICON(dragIcon), child); |
| } |
| |
| } // namespace WebKit |
| |
| #endif // ENABLE(DRAG_SUPPORT) && USE(GTK4) |