blob: c6acb5a276247a25047b6b41b4f4d2b1f1ff57da [file] [log] [blame]
/*
* 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)