18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
2a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Copyright (C) 2009, 2010 Igalia S.L.
321939df44de1705786c545cd1bf519d47250322dBen Murdoch *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is free software; you can redistribute it and/or
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  modify it under the terms of the GNU Lesser General Public
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License as published by the Free Software Foundation; either
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  version 2 of the License, or (at your option) any later version.
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is distributed in the hope that it will be useful,
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  but WITHOUT ANY WARRANTY; without even the implied warranty of
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Lesser General Public License for more details.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  You should have received a copy of the GNU Lesser General Public
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License along with this library; if not, write to the Free Software
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "DragClientGtk.h"
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2221939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "ClipboardGtk.h"
23e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "ClipboardUtilitiesGtk.h"
2421939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "DataObjectGtk.h"
25231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Document.h"
26e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "DragController.h"
27231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Element.h"
28231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Frame.h"
29545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "GOwnPtrGtk.h"
3021939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "GRefPtrGtk.h"
31545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "GtkVersioning.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "NotImplemented.h"
3321939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "PasteboardHelper.h"
34231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "RenderObject.h"
35f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "webkitwebframeprivate.h"
36f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "webkitwebviewprivate.h"
37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "webkitwebview.h"
3868513a70bcd92384395513322f1b801e7bf9c729Steve Block#include <gdk/gdk.h>
39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include <gtk/gtk.h>
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WebCore;
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebKit {
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
45a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#ifdef GTK_API_VERSION_2
46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochstatic gboolean dragIconWindowDrawEventCallback(GtkWidget* widget, GdkEventExpose* event, DragClient* client)
4768513a70bcd92384395513322f1b801e7bf9c729Steve Block{
4828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    RefPtr<cairo_t> context = adoptRef(gdk_cairo_create(event->window));
49a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    client->drawDragIconWindow(widget, context.get());
5068513a70bcd92384395513322f1b801e7bf9c729Steve Block    return TRUE;
5168513a70bcd92384395513322f1b801e7bf9c729Steve Block}
52a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#else
53a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochstatic gboolean dragIconWindowDrawEventCallback(GtkWidget* widget, cairo_t* context, DragClient* client)
54a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!gdk_cairo_get_clip_rectangle(context, 0))
56a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return FALSE;
57a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    client->drawDragIconWindow(widget, context);
58a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return TRUE;
59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
60a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif // GTK_API_VERSION_2
6168513a70bcd92384395513322f1b801e7bf9c729Steve Block
62231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockDragClient::DragClient(WebKitWebView* webView)
63231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    : m_webView(webView)
64231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    , m_startPos(0, 0)
6568513a70bcd92384395513322f1b801e7bf9c729Steve Block    , m_dragIconWindow(gtk_window_new(GTK_WINDOW_POPUP))
66231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#ifdef GTK_API_VERSION_2
6865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    g_signal_connect(m_dragIconWindow, "expose-event", G_CALLBACK(dragIconWindowDrawEventCallback), this);
69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#else
7065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    g_signal_connect(m_dragIconWindow, "draw", G_CALLBACK(dragIconWindowDrawEventCallback), this);
71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif
7268513a70bcd92384395513322f1b801e7bf9c729Steve Block}
7368513a70bcd92384395513322f1b801e7bf9c729Steve Block
7468513a70bcd92384395513322f1b801e7bf9c729Steve BlockDragClient::~DragClient()
7568513a70bcd92384395513322f1b801e7bf9c729Steve Block{
7665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    gtk_widget_destroy(m_dragIconWindow);
77231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
78231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DragClient::willPerformDragDestinationAction(DragDestinationAction, DragData*)
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
83231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid DragClient::willPerformDragSourceAction(DragSourceAction, const IntPoint& startPos, Clipboard*)
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
85231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    m_startPos = startPos;
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectDragDestinationAction DragClient::actionMaskForDrag(DragData*)
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return DragDestinationActionAny;
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectDragSourceAction DragClient::dragSourceActionMaskForPoint(const IntPoint&)
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return DragSourceActionAny;
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10021939df44de1705786c545cd1bf519d47250322dBen Murdochvoid DragClient::startDrag(DragImageRef image, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool linkDrag)
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10221939df44de1705786c545cd1bf519d47250322dBen Murdoch    ClipboardGtk* clipboardGtk = reinterpret_cast<ClipboardGtk*>(clipboard);
103231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
10421939df44de1705786c545cd1bf519d47250322dBen Murdoch    WebKitWebView* webView = webkit_web_frame_get_web_view(kit(frame));
10521939df44de1705786c545cd1bf519d47250322dBen Murdoch    RefPtr<DataObjectGtk> dataObject = clipboardGtk->dataObject();
106cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<GtkTargetList> targetList(clipboardGtk->helper()->targetListForDataObject(dataObject.get()));
107545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    GOwnPtr<GdkEvent> currentEvent(gtk_get_current_event());
108231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
109545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    GdkDragContext* context = gtk_drag_begin(GTK_WIDGET(m_webView), targetList.get(), dragOperationToGdkDragActions(clipboard->sourceOperation()), 1, currentEvent.get());
11068513a70bcd92384395513322f1b801e7bf9c729Steve Block    webView->priv->draggingDataObjects.set(context, dataObject);
111231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
11206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    // A drag starting should prevent a double-click from happening. This might
11306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    // happen if a drag is followed very quickly by another click (like in the DRT).
11406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    webView->priv->previousClickTime = 0;
11506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
11668513a70bcd92384395513322f1b801e7bf9c729Steve Block    // This strategy originally comes from Chromium:
11768513a70bcd92384395513322f1b801e7bf9c729Steve Block    // src/chrome/browser/gtk/tab_contents_drag_source.cc
11868513a70bcd92384395513322f1b801e7bf9c729Steve Block    if (image) {
11968513a70bcd92384395513322f1b801e7bf9c729Steve Block        m_dragImage = image;
12068513a70bcd92384395513322f1b801e7bf9c729Steve Block        IntSize imageSize(cairo_image_surface_get_width(image), cairo_image_surface_get_height(image));
12165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        gtk_window_resize(GTK_WINDOW(m_dragIconWindow), imageSize.width(), imageSize.height());
12268513a70bcd92384395513322f1b801e7bf9c729Steve Block
12365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if (!gtk_widget_get_realized(m_dragIconWindow)) {
12465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            GdkScreen* screen = gtk_widget_get_screen(m_dragIconWindow);
125a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#ifdef GTK_API_VERSION_2
12668513a70bcd92384395513322f1b801e7bf9c729Steve Block            GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen);
12768513a70bcd92384395513322f1b801e7bf9c729Steve Block            if (rgba)
12865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch                gtk_widget_set_colormap(m_dragIconWindow, rgba);
129a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#else
130a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            GdkVisual* visual = gdk_screen_get_rgba_visual(screen);
131a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (!visual)
132a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                visual = gdk_screen_get_system_visual(screen);
13365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            gtk_widget_set_visual(m_dragIconWindow, visual);
134a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif // GTK_API_VERSION_2
13568513a70bcd92384395513322f1b801e7bf9c729Steve Block        }
13668513a70bcd92384395513322f1b801e7bf9c729Steve Block
13768513a70bcd92384395513322f1b801e7bf9c729Steve Block        IntSize origin = eventPos - dragImageOrigin;
13865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        gtk_drag_set_icon_widget(context, m_dragIconWindow,
13968513a70bcd92384395513322f1b801e7bf9c729Steve Block                                 origin.width(), origin.height());
14068513a70bcd92384395513322f1b801e7bf9c729Steve Block    } else
141231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        gtk_drag_set_icon_default(context);
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
144a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid DragClient::drawDragIconWindow(GtkWidget* widget, cairo_t* context)
14568513a70bcd92384395513322f1b801e7bf9c729Steve Block{
146a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    cairo_rectangle(context, 0, 0,
14768513a70bcd92384395513322f1b801e7bf9c729Steve Block                    cairo_image_surface_get_width(m_dragImage.get()),
14868513a70bcd92384395513322f1b801e7bf9c729Steve Block                    cairo_image_surface_get_height(m_dragImage.get()));
149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
150a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    cairo_set_source_surface(context, m_dragImage.get(), 0, 0);
151a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    cairo_fill(context);
15268513a70bcd92384395513322f1b801e7bf9c729Steve Block}
15368513a70bcd92384395513322f1b801e7bf9c729Steve Block
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid DragClient::dragControllerDestroyed()
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    delete this;
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
159