summaryrefslogtreecommitdiffstats
path: root/WebKit/gtk/webkit/webkitwebview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/gtk/webkit/webkitwebview.cpp')
-rw-r--r--WebKit/gtk/webkit/webkitwebview.cpp157
1 files changed, 151 insertions, 6 deletions
diff --git a/WebKit/gtk/webkit/webkitwebview.cpp b/WebKit/gtk/webkit/webkitwebview.cpp
index 62997c5..0010a77 100644
--- a/WebKit/gtk/webkit/webkitwebview.cpp
+++ b/WebKit/gtk/webkit/webkitwebview.cpp
@@ -7,7 +7,7 @@
* Copyright (C) 2008 Gustavo Noronha Silva <gns@gnome.org>
* Copyright (C) 2008 Nuanti Ltd.
* Copyright (C) 2008, 2009, 2010 Collabora Ltd.
- * Copyright (C) 2009 Igalia S.L.
+ * Copyright (C) 2009, 2010 Igalia S.L.
* Copyright (C) 2009 Movial Creative Technologies Inc.
* Copyright (C) 2009 Bobby Powers
*
@@ -52,7 +52,10 @@
#include "Cursor.h"
#include "Document.h"
#include "DocumentLoader.h"
+#include "DragActions.h"
#include "DragClientGtk.h"
+#include "DragController.h"
+#include "DragData.h"
#include "EditorClientGtk.h"
#include "Editor.h"
#include "EventHandler.h"
@@ -123,6 +126,7 @@
static const double defaultDPI = 96.0;
static WebKitCacheModel cacheModel;
+static IntPoint globalPointForClientPoint(GdkWindow* window, const IntPoint& clientPoint);
using namespace WebKit;
using namespace WebCore;
@@ -370,9 +374,6 @@ static gboolean webkit_web_view_popup_menu_handler(GtkWidget* widget)
location = IntPoint(rightAligned ? firstRect.right() : firstRect.x(), firstRect.bottom());
}
- int x, y;
- gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient())), &x, &y);
-
// FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in the selected element.
// Ideally we'd have the position of a context menu event be separate from its target node.
location = view->contentsToWindow(location) + IntSize(0, -1);
@@ -384,7 +385,7 @@ static gboolean webkit_web_view_popup_menu_handler(GtkWidget* widget)
location.setX(contextMenuMargin);
else if (location.x() > view->width())
location.setX(view->width() - contextMenuMargin);
- IntPoint global = location + IntSize(x, y);
+ IntPoint global(globalPointForClientPoint(gtk_widget_get_window(widget), location));
PlatformMouseEvent event(location, global, RightButton, MouseEventPressed, 0, false, false, false, false, gtk_get_current_event_time());
@@ -1197,6 +1198,10 @@ static void webkit_web_view_dispose(GObject* object)
}
priv->draggingDataObjects->clear();
+ HashMap<GdkDragContext*, DroppingContext*>::iterator endDroppingContexts = priv->droppingContexts->end();
+ for (HashMap<GdkDragContext*, DroppingContext*>::iterator iter = priv->droppingContexts->begin(); iter != endDroppingContexts; ++iter)
+ delete (iter->second);
+ priv->droppingContexts->clear();
G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object);
}
@@ -1214,6 +1219,7 @@ static void webkit_web_view_finalize(GObject* object)
delete priv->previousClickPoint;
delete priv->draggingDataObjects;
+ delete priv->droppingContexts;
G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object);
}
@@ -1309,6 +1315,14 @@ static void webkit_web_view_screen_changed(GtkWidget* widget, GdkScreen* previou
settings->setMinimumLogicalFontSize(minimumLogicalFontSize / 72.0 * DPI);
}
+static IntPoint globalPointForClientPoint(GdkWindow* window, const IntPoint& clientPoint)
+{
+ int x, y;
+ gdk_window_get_origin(window, &x, &y);
+ return clientPoint + IntSize(x, y);
+}
+
+
static void webkit_web_view_drag_end(GtkWidget* widget, GdkDragContext* context)
{
WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
@@ -1360,6 +1374,130 @@ static void webkit_web_view_drag_data_get(GtkWidget* widget, GdkDragContext* con
pasteboardHelperInstance()->fillSelectionData(selectionData, info, priv->draggingDataObjects->get(context).get());
}
+static gboolean doDragLeaveLater(DroppingContext* context)
+{
+ WebKitWebView* webView = context->webView;
+ WebKitWebViewPrivate* priv = webView->priv;
+
+ if (!priv->droppingContexts->contains(context->gdkContext))
+ return FALSE;
+
+ // If the view doesn't know about the drag yet (there are still pending data)
+ // requests, don't update it with information about the drag.
+ if (context->pendingDataRequests)
+ return FALSE;
+
+ // Don't call dragExited if we have just received a drag-drop signal. This
+ // happens in the case of a successful drop onto the view.
+ if (!context->dropHappened) {
+ const IntPoint& position = context->lastMotionPosition;
+ DragData dragData(context->dataObject.get(), position, globalPointForClientPoint(gtk_widget_get_window(GTK_WIDGET(webView)), position), DragOperationNone);
+ core(webView)->dragController()->dragExited(&dragData);
+ }
+
+ core(webView)->dragController()->dragEnded();
+ priv->droppingContexts->remove(context->gdkContext);
+ delete context;
+ return FALSE;
+}
+
+static void webkit_web_view_drag_leave(GtkWidget* widget, GdkDragContext* context, guint time)
+{
+ WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
+ WebKitWebViewPrivate* priv = webView->priv;
+
+ if (!priv->droppingContexts->contains(context))
+ return;
+
+ // During a drop GTK+ will fire a drag-leave signal right before firing
+ // the drag-drop signal. We want the actions for drag-leave to happen after
+ // those for drag-drop, so schedule them to happen asynchronously here.
+ g_timeout_add(0, reinterpret_cast<GSourceFunc>(doDragLeaveLater), priv->droppingContexts->get(context));
+}
+
+static gboolean webkit_web_view_drag_motion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
+{
+ WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
+ WebKitWebViewPrivate* priv = webView->priv;
+
+ DroppingContext* droppingContext = 0;
+ IntPoint position = IntPoint(x, y);
+ if (!priv->droppingContexts->contains(context)) {
+ droppingContext = new DroppingContext;
+ droppingContext->webView = webView;
+ droppingContext->gdkContext = context;
+ droppingContext->dataObject = WebCore::DataObjectGtk::create();
+ droppingContext->dropHappened = false;
+ droppingContext->lastMotionPosition = position;
+ priv->droppingContexts->set(context, droppingContext);
+
+ Vector<GdkAtom> acceptableTargets(pasteboardHelperInstance()->dropAtomsForContext(widget, context));
+ droppingContext->pendingDataRequests = acceptableTargets.size();
+ for (size_t i = 0; i < acceptableTargets.size(); i++)
+ gtk_drag_get_data(widget, context, acceptableTargets.at(i), time);
+ } else {
+ droppingContext = priv->droppingContexts->get(context);
+ droppingContext->lastMotionPosition = position;
+ }
+
+ // Don't send any drag information to WebCore until we've retrieved all
+ // the data for this drag operation. Otherwise we'd have to block to wait
+ // for the drag's data.
+ ASSERT(droppingContext);
+ if (droppingContext->pendingDataRequests > 0)
+ return TRUE;
+
+ DragData dragData(droppingContext->dataObject.get(), position, globalPointForClientPoint(gtk_widget_get_window(widget), position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
+ DragOperation operation = core(webView)->dragController()->dragUpdated(&dragData);
+ gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time);
+
+ return TRUE;
+}
+
+static void webkit_web_view_drag_data_received(GtkWidget* widget, GdkDragContext* context, gint x, gint y, GtkSelectionData* selectionData, guint info, guint time)
+{
+ WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
+ WebKitWebViewPrivate* priv = webView->priv;
+
+ if (!priv->droppingContexts->contains(context))
+ return;
+
+ DroppingContext* droppingContext = priv->droppingContexts->get(context);
+ droppingContext->pendingDataRequests--;
+ pasteboardHelperInstance()->fillDataObjectFromDropData(selectionData, info, droppingContext->dataObject.get());
+
+ if (droppingContext->pendingDataRequests)
+ return;
+
+ // The coordinates passed to drag-data-received signal are sometimes
+ // inaccurate in DRT, so use the coordinates of the last motion event.
+ const IntPoint& position = droppingContext->lastMotionPosition;
+
+ // If there are no more pending requests, start sending dragging data to WebCore.
+ DragData dragData(droppingContext->dataObject.get(), position, globalPointForClientPoint(gtk_widget_get_window(widget), position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
+ DragOperation operation = core(webView)->dragController()->dragEntered(&dragData);
+ gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time);
+}
+
+static gboolean webkit_web_view_drag_drop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
+{
+ WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
+ WebKitWebViewPrivate* priv = webView->priv;
+
+ if (!priv->droppingContexts->contains(context))
+ return FALSE;
+
+ DroppingContext* droppingContext = priv->droppingContexts->get(context);
+ droppingContext->dropHappened = true;
+
+ IntPoint position(x, y);
+ DragData dragData(droppingContext->dataObject.get(), position, globalPointForClientPoint(gtk_widget_get_window(widget), position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
+ core(webView)->dragController()->performDrag(&dragData);
+
+ gtk_drag_finish(context, TRUE, FALSE, time);
+ return TRUE;
+}
+
#if GTK_CHECK_VERSION(2, 12, 0)
static gboolean webkit_web_view_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip)
{
@@ -2356,6 +2494,10 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
widgetClass->screen_changed = webkit_web_view_screen_changed;
widgetClass->drag_end = webkit_web_view_drag_end;
widgetClass->drag_data_get = webkit_web_view_drag_data_get;
+ widgetClass->drag_motion = webkit_web_view_drag_motion;
+ widgetClass->drag_leave = webkit_web_view_drag_leave;
+ widgetClass->drag_drop = webkit_web_view_drag_drop;
+ widgetClass->drag_data_received = webkit_web_view_drag_data_received;
#if GTK_CHECK_VERSION(2, 12, 0)
widgetClass->query_tooltip = webkit_web_view_query_tooltip;
#endif
@@ -2900,7 +3042,7 @@ static void webkit_web_view_init(WebKitWebView* webView)
priv->imContext = gtk_im_multicontext_new();
WebKit::InspectorClient* inspectorClient = new WebKit::InspectorClient(webView);
- priv->corePage = new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient(webView), new WebKit::EditorClient(webView), new WebKit::DragClient(webView), inspectorClient, 0, 0, 0);
+ priv->corePage = new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient(webView), new WebKit::EditorClient(webView), new WebKit::DragClient(webView), inspectorClient, 0, 0, 0, 0);
// We also add a simple wrapper class to provide the public
// interface for the Web Inspector.
@@ -2937,6 +3079,9 @@ static void webkit_web_view_init(WebKitWebView* webView)
priv->previousClickTime = 0;
priv->draggingDataObjects = new HashMap<GdkDragContext*, RefPtr<WebCore::DataObjectGtk> >();
+ priv->droppingContexts = new HashMap<GdkDragContext*, DroppingContext*>();
+ gtk_drag_dest_set(GTK_WIDGET(webView), static_cast<GtkDestDefaults>(0), 0, 0, static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
+ gtk_drag_dest_set_target_list(GTK_WIDGET(webView), pasteboardHelperInstance()->targetList());
}
GtkWidget* webkit_web_view_new(void)