~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/gtk/GtkDragAndDropHelper.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011, Igalia S.L.
 
3
 *
 
4
 *  This library is free software; you can redistribute it and/or
 
5
 *  modify it under the terms of the GNU Lesser General Public
 
6
 *  License as published by the Free Software Foundation; either
 
7
 *  version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 *  This library is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 *  Lesser General Public License for more details.
 
13
 *
 
14
 *  You should have received a copy of the GNU Lesser General Public
 
15
 *  License along with this library; if not, write to the Free Software
 
16
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
#include "GtkDragAndDropHelper.h"
 
21
 
 
22
#include "ClipboardUtilitiesGtk.h"
 
23
#include "DragData.h"
 
24
#include "GtkUtilities.h"
 
25
#include "GtkVersioning.h"
 
26
#include "PasteboardHelper.h"
 
27
#include <gtk/gtk.h>
 
28
#include <wtf/PassOwnPtr.h>
 
29
 
 
30
namespace WebCore {
 
31
 
 
32
struct DroppingContext {
 
33
    DroppingContext(GdkDragContext* gdkContext, const IntPoint& position)
 
34
        : gdkContext(gdkContext)
 
35
        , dataObject(DataObjectGtk::create())
 
36
        , lastMotionPosition(position)
 
37
        , dropHappened(false)
 
38
        , exitedCallback(0)
 
39
    {
 
40
    }
 
41
 
 
42
    GdkDragContext* gdkContext;
 
43
    RefPtr<WebCore::DataObjectGtk> dataObject;
 
44
    WebCore::IntPoint lastMotionPosition;
 
45
    int pendingDataRequests;
 
46
    bool dropHappened;
 
47
    DragExitedCallback exitedCallback;
 
48
};
 
49
 
 
50
typedef HashMap<GdkDragContext*, DroppingContext*> DroppingContextMap;
 
51
typedef HashMap<GdkDragContext*, RefPtr<DataObjectGtk> > DraggingDataObjectsMap;
 
52
 
 
53
GtkDragAndDropHelper::~GtkDragAndDropHelper()
 
54
{
 
55
    deleteAllValues(m_droppingContexts);
 
56
}
 
57
 
 
58
bool GtkDragAndDropHelper::handleDragEnd(GdkDragContext* dragContext)
 
59
{
 
60
    DraggingDataObjectsMap::iterator iterator = m_draggingDataObjects.find(dragContext);
 
61
    if (iterator == m_draggingDataObjects.end())
 
62
        return false;
 
63
 
 
64
    m_draggingDataObjects.remove(iterator);
 
65
    return true;
 
66
}
 
67
 
 
68
void GtkDragAndDropHelper::handleGetDragData(GdkDragContext* context, GtkSelectionData* selectionData, guint info)
 
69
{
 
70
    DraggingDataObjectsMap::iterator iterator = m_draggingDataObjects.find(context);
 
71
    if (iterator == m_draggingDataObjects.end())
 
72
        return;
 
73
    PasteboardHelper::defaultPasteboardHelper()->fillSelectionData(selectionData, info, iterator->value.get());
 
74
}
 
75
 
 
76
struct HandleDragLaterData {
 
77
    DroppingContext* context;
 
78
    GtkDragAndDropHelper* glue;
 
79
};
 
80
 
 
81
static gboolean handleDragLeaveLaterCallback(HandleDragLaterData* data)
 
82
{
 
83
    data->glue->handleDragLeaveLater(data->context);
 
84
    delete data;
 
85
    return FALSE;
 
86
}
 
87
 
 
88
void GtkDragAndDropHelper::handleDragLeaveLater(DroppingContext* context)
 
89
{
 
90
    DroppingContextMap::iterator iterator = m_droppingContexts.find(context->gdkContext);
 
91
    if (iterator == m_droppingContexts.end())
 
92
        return;
 
93
 
 
94
    // If the view doesn't know about the drag yet (there are still pending data)
 
95
    // requests, don't update it with information about the drag.
 
96
    if (context->pendingDataRequests)
 
97
        return;
 
98
 
 
99
    const IntPoint& position = context->lastMotionPosition;
 
100
    DragData dragData(context->dataObject.get(), position,
 
101
                      convertWidgetPointToScreenPoint(m_widget, position),
 
102
                      DragOperationNone);
 
103
    context->exitedCallback(m_widget, &dragData, context->dropHappened);
 
104
 
 
105
    m_droppingContexts.remove(iterator);
 
106
    delete context;
 
107
}
 
108
 
 
109
void GtkDragAndDropHelper::handleDragLeave(GdkDragContext* gdkContext, DragExitedCallback exitedCallback)
 
110
{
 
111
    DroppingContextMap::iterator iterator = m_droppingContexts.find(gdkContext);
 
112
    if (iterator == m_droppingContexts.end())
 
113
        return;
 
114
 
 
115
    // During a drop GTK+ will fire a drag-leave signal right before firing
 
116
    // the drag-drop signal. We want the actions for drag-leave to happen after
 
117
    // those for drag-drop, so schedule them to happen asynchronously here.
 
118
    HandleDragLaterData* data = new HandleDragLaterData;
 
119
    data->context = iterator->value;
 
120
    data->context->exitedCallback = exitedCallback;
 
121
    data->glue = this;
 
122
    g_timeout_add(0, reinterpret_cast<GSourceFunc>(handleDragLeaveLaterCallback), data);
 
123
}
 
124
 
 
125
static void queryNewDropContextData(DroppingContext* dropContext, GtkWidget* widget, guint time)
 
126
{
 
127
    GdkDragContext* gdkContext = dropContext->gdkContext;
 
128
    Vector<GdkAtom> acceptableTargets(PasteboardHelper::defaultPasteboardHelper()->dropAtomsForContext(widget, gdkContext));
 
129
    dropContext->pendingDataRequests = acceptableTargets.size();
 
130
    for (size_t i = 0; i < acceptableTargets.size(); i++)
 
131
        gtk_drag_get_data(widget, gdkContext, acceptableTargets.at(i), time);
 
132
}
 
133
 
 
134
PassOwnPtr<DragData> GtkDragAndDropHelper::handleDragMotion(GdkDragContext* context, const IntPoint& position, unsigned time)
 
135
{
 
136
    DroppingContext* droppingContext = 0;
 
137
    DroppingContextMap::iterator iterator = m_droppingContexts.find(context);
 
138
    if (iterator == m_droppingContexts.end()) {
 
139
        droppingContext = new DroppingContext(context, position);
 
140
        m_droppingContexts.set(context, droppingContext);
 
141
        queryNewDropContextData(droppingContext, m_widget, time);
 
142
    } else {
 
143
        droppingContext = iterator->value;
 
144
        droppingContext->lastMotionPosition = position;
 
145
    }
 
146
 
 
147
    // Don't send any drag information to WebCore until we've retrieved all
 
148
    // the data for this drag operation. Otherwise we'd have to block to wait
 
149
    // for the drag's data.
 
150
    ASSERT(droppingContext);
 
151
    if (droppingContext->pendingDataRequests > 0)
 
152
        return adoptPtr(static_cast<DragData*>(0));
 
153
 
 
154
    return adoptPtr(new DragData(droppingContext->dataObject.get(), position,
 
155
                                 convertWidgetPointToScreenPoint(m_widget, position),
 
156
                                 gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))));
 
157
}
 
158
 
 
159
PassOwnPtr<DragData> GtkDragAndDropHelper::handleDragDataReceived(GdkDragContext* context, GtkSelectionData* selectionData, guint info)
 
160
{
 
161
    DroppingContextMap::iterator iterator = m_droppingContexts.find(context);
 
162
    if (iterator == m_droppingContexts.end())
 
163
        return adoptPtr(static_cast<DragData*>(0));
 
164
 
 
165
    DroppingContext* droppingContext = iterator->value;
 
166
    droppingContext->pendingDataRequests--;
 
167
    PasteboardHelper::defaultPasteboardHelper()->fillDataObjectFromDropData(selectionData, info, droppingContext->dataObject.get());
 
168
 
 
169
    if (droppingContext->pendingDataRequests)
 
170
        return adoptPtr(static_cast<DragData*>(0));
 
171
 
 
172
    // The coordinates passed to drag-data-received signal are sometimes
 
173
    // inaccurate in DRT, so use the coordinates of the last motion event.
 
174
    const IntPoint& position = droppingContext->lastMotionPosition;
 
175
 
 
176
    // If there are no more pending requests, start sending dragging data to WebCore.
 
177
    return adoptPtr(new DragData(droppingContext->dataObject.get(), position, 
 
178
                                 convertWidgetPointToScreenPoint(m_widget, position),
 
179
                                 gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))));
 
180
}
 
181
 
 
182
PassOwnPtr<DragData> GtkDragAndDropHelper::handleDragDrop(GdkDragContext* context, const IntPoint& position)
 
183
{
 
184
    DroppingContextMap::iterator iterator = m_droppingContexts.find(context);
 
185
    if (iterator == m_droppingContexts.end())
 
186
        return adoptPtr(static_cast<DragData*>(0));
 
187
 
 
188
    DroppingContext* droppingContext = iterator->value;
 
189
    droppingContext->dropHappened = true;
 
190
 
 
191
    return adoptPtr(new DragData(droppingContext->dataObject.get(), position, 
 
192
                                 convertWidgetPointToScreenPoint(m_widget, position),
 
193
                                 gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))));
 
194
}
 
195
 
 
196
void GtkDragAndDropHelper::startedDrag(GdkDragContext* context, DataObjectGtk* dataObject)
 
197
{
 
198
    m_draggingDataObjects.set(context, dataObject);
 
199
}
 
200
 
 
201
} // namespace WebCore