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/PassOwnPtr.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<WebCore::DataObjectGtk> dataObject;
WebCore::IntPoint lastMotionPosition;
int pendingDataRequests;
bool dropHappened;
DragExitedCallback exitedCallback;
};
typedef HashMap<GdkDragContext*, DroppingContext*> DroppingContextMap;
typedef HashMap<GdkDragContext*, RefPtr<DataObjectGtk> > DraggingDataObjectsMap;
GtkDragAndDropHelper::~GtkDragAndDropHelper()
{
deleteAllValues(m_droppingContexts);
}
bool GtkDragAndDropHelper::handleDragEnd(GdkDragContext* dragContext)
{
DraggingDataObjectsMap::iterator iterator = m_draggingDataObjects.find(dragContext);
if (iterator == m_draggingDataObjects.end())
return false;
m_draggingDataObjects.remove(iterator);
return true;
}
void GtkDragAndDropHelper::handleGetDragData(GdkDragContext* context, GtkSelectionData* selectionData, guint info)
{
DraggingDataObjectsMap::iterator iterator = m_draggingDataObjects.find(context);
if (iterator == m_draggingDataObjects.end())
return;
PasteboardHelper::defaultPasteboardHelper()->fillSelectionData(selectionData, info, iterator->second.get());
}
struct HandleDragLaterData {
DroppingContext* context;
GtkDragAndDropHelper* glue;
};
static gboolean handleDragLeaveLaterCallback(HandleDragLaterData* data)
{
data->glue->handleDragLeaveLater(data->context);
delete data;
return FALSE;
}
void GtkDragAndDropHelper::handleDragLeaveLater(DroppingContext* context)
{
DroppingContextMap::iterator 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);
delete context;
}
void GtkDragAndDropHelper::handleDragLeave(GdkDragContext* gdkContext, DragExitedCallback exitedCallback)
{
DroppingContextMap::iterator iterator = m_droppingContexts.find(gdkContext);
if (iterator == m_droppingContexts.end())
return;
HandleDragLaterData* data = new HandleDragLaterData;
data->context = iterator->second;
data->context->exitedCallback = exitedCallback;
data->glue = this;
g_timeout_add(0, reinterpret_cast<GSourceFunc>(handleDragLeaveLaterCallback), data);
}
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);
}
PassOwnPtr<DragData> GtkDragAndDropHelper::handleDragMotion(GdkDragContext* context, const IntPoint& position, unsigned time)
{
DroppingContext* droppingContext = 0;
DroppingContextMap::iterator iterator = m_droppingContexts.find(context);
if (iterator == m_droppingContexts.end()) {
droppingContext = new DroppingContext(context, position);
m_droppingContexts.set(context, droppingContext);
queryNewDropContextData(droppingContext, m_widget, time);
} else {
droppingContext = iterator->second;
droppingContext->lastMotionPosition = position;
}
ASSERT(droppingContext);
if (droppingContext->pendingDataRequests > 0)
return adoptPtr(static_cast<DragData*>(0));
return adoptPtr(new DragData(droppingContext->dataObject.get(), position,
convertWidgetPointToScreenPoint(m_widget, position),
gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))));
}
PassOwnPtr<DragData> GtkDragAndDropHelper::handleDragDataReceived(GdkDragContext* context, GtkSelectionData* selectionData, guint info)
{
DroppingContextMap::iterator iterator = m_droppingContexts.find(context);
if (iterator == m_droppingContexts.end())
return adoptPtr(static_cast<DragData*>(0));
DroppingContext* droppingContext = iterator->second;
droppingContext->pendingDataRequests--;
PasteboardHelper::defaultPasteboardHelper()->fillDataObjectFromDropData(selectionData, info, droppingContext->dataObject.get());
if (droppingContext->pendingDataRequests)
return adoptPtr(static_cast<DragData*>(0));
const IntPoint& position = droppingContext->lastMotionPosition;
return adoptPtr(new DragData(droppingContext->dataObject.get(), position,
convertWidgetPointToScreenPoint(m_widget, position),
gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))));
}
PassOwnPtr<DragData> GtkDragAndDropHelper::handleDragDrop(GdkDragContext* context, const IntPoint& position)
{
DroppingContextMap::iterator iterator = m_droppingContexts.find(context);
if (iterator == m_droppingContexts.end())
return adoptPtr(static_cast<DragData*>(0));
DroppingContext* droppingContext = iterator->second;
droppingContext->dropHappened = true;
return adoptPtr(new DragData(droppingContext->dataObject.get(), position,
convertWidgetPointToScreenPoint(m_widget, position),
gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))));
}
void GtkDragAndDropHelper::startedDrag(GdkDragContext* context, DataObjectGtk* dataObject)
{
m_draggingDataObjects.set(context, dataObject);
}
}