GtkDragAndDropHelper.cpp [plain text]
#include "config.h"
#include "GtkDragAndDropHelper.h"
#include "ClipboardUtilitiesGtk.h"
#include "DragData.h"
#include "GtkUtilities.h"
#include "GtkVersioning.h"
#include "PasteboardHelper.h"
#include <gtk/gtk.h>
#include <wtf/gobject/GMainLoopSource.h>
namespace WebCore {
struct DroppingContext {
DroppingContext(GdkDragContext* gdkContext, const IntPoint& position)
: gdkContext(gdkContext)
, dataObject(DataObjectGtk::create())
, lastMotionPosition(position)
, dropHappened(false)
, exitedCallback(0)
{
}
GdkDragContext* gdkContext;
RefPtr<DataObjectGtk> dataObject;
WebCore::IntPoint lastMotionPosition;
int pendingDataRequests;
bool dropHappened;
DragExitedCallback exitedCallback;
};
GtkDragAndDropHelper::GtkDragAndDropHelper()
: m_widget(nullptr)
{
}
GtkDragAndDropHelper::~GtkDragAndDropHelper()
{
}
bool GtkDragAndDropHelper::handleDragEnd(GdkDragContext* dragContext)
{
return m_draggingDataObjects.remove(dragContext);
}
void GtkDragAndDropHelper::handleGetDragData(GdkDragContext* context, GtkSelectionData* selectionData, guint info)
{
DataObjectGtk* dataObject = m_draggingDataObjects.get(context);
if (!dataObject)
return;
PasteboardHelper::defaultPasteboardHelper()->fillSelectionData(selectionData, info, dataObject);
}
void GtkDragAndDropHelper::handleDragLeaveLater(DroppingContext* context)
{
auto iterator = m_droppingContexts.find(context->gdkContext);
if (iterator == m_droppingContexts.end())
return;
if (context->pendingDataRequests)
return;
const IntPoint& position = context->lastMotionPosition;
DragData dragData(context->dataObject.get(), position,
convertWidgetPointToScreenPoint(m_widget, position),
DragOperationNone);
context->exitedCallback(m_widget, dragData, context->dropHappened);
m_droppingContexts.remove(iterator);
}
void GtkDragAndDropHelper::handleDragLeave(GdkDragContext* gdkContext, DragExitedCallback exitedCallback)
{
DroppingContext* context = m_droppingContexts.get(gdkContext);
if (!context)
return;
context->exitedCallback = exitedCallback;
GMainLoopSource::createAndDeleteOnDestroy().schedule("[WebKit] handleDragLeaveLater", std::function<void()>(std::bind(&GtkDragAndDropHelper::handleDragLeaveLater, this, context)));
}
static void queryNewDropContextData(DroppingContext* dropContext, GtkWidget* widget, guint time)
{
GdkDragContext* gdkContext = dropContext->gdkContext;
Vector<GdkAtom> acceptableTargets(PasteboardHelper::defaultPasteboardHelper()->dropAtomsForContext(widget, gdkContext));
dropContext->pendingDataRequests = acceptableTargets.size();
for (size_t i = 0; i < acceptableTargets.size(); i++)
gtk_drag_get_data(widget, gdkContext, acceptableTargets.at(i), time);
}
DataObjectGtk* GtkDragAndDropHelper::handleDragMotion(GdkDragContext* context, const IntPoint& position, unsigned time)
{
std::unique_ptr<DroppingContext>& droppingContext = m_droppingContexts.add(context, nullptr).iterator->value;
if (!droppingContext) {
droppingContext = std::make_unique<DroppingContext>(context, position);
queryNewDropContextData(droppingContext.get(), m_widget, time);
} else
droppingContext->lastMotionPosition = position;
if (droppingContext->pendingDataRequests > 0)
return nullptr;
return droppingContext->dataObject.get();
}
DataObjectGtk* GtkDragAndDropHelper::handleDragDataReceived(GdkDragContext* context, GtkSelectionData* selectionData, unsigned info, IntPoint& position)
{
DroppingContext* droppingContext = m_droppingContexts.get(context);
if (!droppingContext)
return nullptr;
droppingContext->pendingDataRequests--;
PasteboardHelper::defaultPasteboardHelper()->fillDataObjectFromDropData(selectionData, info, droppingContext->dataObject.get());
if (droppingContext->pendingDataRequests)
return nullptr;
position = droppingContext->lastMotionPosition;
return droppingContext->dataObject.get();
}
DataObjectGtk* GtkDragAndDropHelper::handleDragDrop(GdkDragContext* context)
{
DroppingContext* droppingContext = m_droppingContexts.get(context);
if (!droppingContext)
return nullptr;
droppingContext->dropHappened = true;
return droppingContext->dataObject.get();
}
void GtkDragAndDropHelper::startedDrag(GdkDragContext* context, DataObjectGtk* dataObject)
{
m_draggingDataObjects.set(context, dataObject);
}
}