1 /* 2 * Copyright (C) 2009, 2010 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 "DragClientGtk.h" 21 22 #include "ClipboardGtk.h" 23 #include "ClipboardUtilitiesGtk.h" 24 #include "DataObjectGtk.h" 25 #include "Document.h" 26 #include "DragController.h" 27 #include "Element.h" 28 #include "Frame.h" 29 #include "GOwnPtrGtk.h" 30 #include "GRefPtrGtk.h" 31 #include "GtkVersioning.h" 32 #include "NotImplemented.h" 33 #include "PasteboardHelper.h" 34 #include "RenderObject.h" 35 #include "webkitwebframeprivate.h" 36 #include "webkitwebviewprivate.h" 37 #include "webkitwebview.h" 38 #include <gdk/gdk.h> 39 #include <gtk/gtk.h> 40 41 using namespace WebCore; 42 43 namespace WebKit { 44 45 #ifdef GTK_API_VERSION_2 46 static gboolean dragIconWindowDrawEventCallback(GtkWidget* widget, GdkEventExpose* event, DragClient* client) 47 { 48 RefPtr<cairo_t> context = adoptRef(gdk_cairo_create(event->window)); 49 client->drawDragIconWindow(widget, context.get()); 50 return TRUE; 51 } 52 #else 53 static gboolean dragIconWindowDrawEventCallback(GtkWidget* widget, cairo_t* context, DragClient* client) 54 { 55 if (!gdk_cairo_get_clip_rectangle(context, 0)) 56 return FALSE; 57 client->drawDragIconWindow(widget, context); 58 return TRUE; 59 } 60 #endif // GTK_API_VERSION_2 61 62 DragClient::DragClient(WebKitWebView* webView) 63 : m_webView(webView) 64 , m_startPos(0, 0) 65 , m_dragIconWindow(gtk_window_new(GTK_WINDOW_POPUP)) 66 { 67 #ifdef GTK_API_VERSION_2 68 g_signal_connect(m_dragIconWindow, "expose-event", G_CALLBACK(dragIconWindowDrawEventCallback), this); 69 #else 70 g_signal_connect(m_dragIconWindow, "draw", G_CALLBACK(dragIconWindowDrawEventCallback), this); 71 #endif 72 } 73 74 DragClient::~DragClient() 75 { 76 gtk_widget_destroy(m_dragIconWindow); 77 } 78 79 void DragClient::willPerformDragDestinationAction(DragDestinationAction, DragData*) 80 { 81 } 82 83 void DragClient::willPerformDragSourceAction(DragSourceAction, const IntPoint& startPos, Clipboard*) 84 { 85 m_startPos = startPos; 86 } 87 88 DragDestinationAction DragClient::actionMaskForDrag(DragData*) 89 { 90 notImplemented(); 91 return DragDestinationActionAny; 92 } 93 94 DragSourceAction DragClient::dragSourceActionMaskForPoint(const IntPoint&) 95 { 96 notImplemented(); 97 return DragSourceActionAny; 98 } 99 100 void DragClient::startDrag(DragImageRef image, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool linkDrag) 101 { 102 ClipboardGtk* clipboardGtk = reinterpret_cast<ClipboardGtk*>(clipboard); 103 104 WebKitWebView* webView = webkit_web_frame_get_web_view(kit(frame)); 105 RefPtr<DataObjectGtk> dataObject = clipboardGtk->dataObject(); 106 GRefPtr<GtkTargetList> targetList(clipboardGtk->helper()->targetListForDataObject(dataObject.get())); 107 GOwnPtr<GdkEvent> currentEvent(gtk_get_current_event()); 108 109 GdkDragContext* context = gtk_drag_begin(GTK_WIDGET(m_webView), targetList.get(), dragOperationToGdkDragActions(clipboard->sourceOperation()), 1, currentEvent.get()); 110 webView->priv->draggingDataObjects.set(context, dataObject); 111 112 // A drag starting should prevent a double-click from happening. This might 113 // happen if a drag is followed very quickly by another click (like in the DRT). 114 webView->priv->previousClickTime = 0; 115 116 // This strategy originally comes from Chromium: 117 // src/chrome/browser/gtk/tab_contents_drag_source.cc 118 if (image) { 119 m_dragImage = image; 120 IntSize imageSize(cairo_image_surface_get_width(image), cairo_image_surface_get_height(image)); 121 gtk_window_resize(GTK_WINDOW(m_dragIconWindow), imageSize.width(), imageSize.height()); 122 123 if (!gtk_widget_get_realized(m_dragIconWindow)) { 124 GdkScreen* screen = gtk_widget_get_screen(m_dragIconWindow); 125 #ifdef GTK_API_VERSION_2 126 GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen); 127 if (rgba) 128 gtk_widget_set_colormap(m_dragIconWindow, rgba); 129 #else 130 GdkVisual* visual = gdk_screen_get_rgba_visual(screen); 131 if (!visual) 132 visual = gdk_screen_get_system_visual(screen); 133 gtk_widget_set_visual(m_dragIconWindow, visual); 134 #endif // GTK_API_VERSION_2 135 } 136 137 IntSize origin = eventPos - dragImageOrigin; 138 gtk_drag_set_icon_widget(context, m_dragIconWindow, 139 origin.width(), origin.height()); 140 } else 141 gtk_drag_set_icon_default(context); 142 } 143 144 void DragClient::drawDragIconWindow(GtkWidget* widget, cairo_t* context) 145 { 146 cairo_rectangle(context, 0, 0, 147 cairo_image_surface_get_width(m_dragImage.get()), 148 cairo_image_surface_get_height(m_dragImage.get())); 149 cairo_set_operator(context, CAIRO_OPERATOR_SOURCE); 150 cairo_set_source_surface(context, m_dragImage.get(), 0, 0); 151 cairo_fill(context); 152 } 153 154 void DragClient::dragControllerDestroyed() 155 { 156 delete this; 157 } 158 } 159