1 /* 2 * Copyright (C) 2007 Luca Bruno <lethalman88 (at) gmail.com> 3 * Copyright (C) 2009 Holger Hans Peter Freyther 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #include "config.h" 21 #include "PasteboardHelperGtk.h" 22 23 #include "DataObjectGtk.h" 24 #include "FocusController.h" 25 #include "Frame.h" 26 #include <gtk/gtk.h> 27 #include "webkitwebframe.h" 28 #include "webkitwebview.h" 29 #include "webkitprivate.h" 30 31 using namespace WebCore; 32 33 namespace WebKit { 34 35 static GdkAtom gdkMarkupAtom = gdk_atom_intern("text/html", FALSE); 36 37 PasteboardHelperGtk::PasteboardHelperGtk() 38 : m_targetList(gtk_target_list_new(0, 0)) 39 { 40 gtk_target_list_add_text_targets(m_targetList, WEBKIT_WEB_VIEW_TARGET_INFO_TEXT); 41 gtk_target_list_add(m_targetList, gdkMarkupAtom, 0, WEBKIT_WEB_VIEW_TARGET_INFO_HTML); 42 } 43 44 PasteboardHelperGtk::~PasteboardHelperGtk() 45 { 46 gtk_target_list_unref(m_targetList); 47 } 48 49 GtkClipboard* PasteboardHelperGtk::getCurrentTarget(Frame* frame) const 50 { 51 WebKitWebView* webView = webkit_web_frame_get_web_view(kit(frame)); 52 53 if (webkit_web_view_use_primary_for_paste(webView)) 54 return getPrimary(frame); 55 else 56 return getClipboard(frame); 57 } 58 59 GtkClipboard* PasteboardHelperGtk::getClipboard(Frame* frame) const 60 { 61 WebKitWebView* webView = webkit_web_frame_get_web_view(kit(frame)); 62 return gtk_widget_get_clipboard(GTK_WIDGET (webView), 63 GDK_SELECTION_CLIPBOARD); 64 } 65 66 GtkClipboard* PasteboardHelperGtk::getPrimary(Frame* frame) const 67 { 68 WebKitWebView* webView = webkit_web_frame_get_web_view(kit(frame)); 69 return gtk_widget_get_clipboard(GTK_WIDGET (webView), 70 GDK_SELECTION_PRIMARY); 71 } 72 73 GtkTargetList* PasteboardHelperGtk::targetList() const 74 { 75 return m_targetList; 76 } 77 78 gint PasteboardHelperGtk::getWebViewTargetInfoHtml() const 79 { 80 return WEBKIT_WEB_VIEW_TARGET_INFO_HTML; 81 } 82 83 static void fillSelectionData(GtkSelectionData* selectionData, guint info, DataObjectGtk* dataObject) 84 { 85 if (info == WEBKIT_WEB_VIEW_TARGET_INFO_TEXT) 86 gtk_selection_data_set_text(selectionData, dataObject->text().utf8().data(), -1); 87 else if (info == WEBKIT_WEB_VIEW_TARGET_INFO_HTML) { 88 GOwnPtr<gchar> markup(g_strdup(dataObject->markup().utf8().data())); 89 gtk_selection_data_set(selectionData, selectionData->target, 8, 90 reinterpret_cast<const guchar*>(markup.get()), 91 strlen(markup.get())); 92 } 93 } 94 95 static GtkTargetList* targetListForDataObject(DataObjectGtk* dataObject) 96 { 97 GtkTargetList* list = gtk_target_list_new(0, 0); 98 99 if (dataObject->hasText()) 100 gtk_target_list_add_text_targets(list, WEBKIT_WEB_VIEW_TARGET_INFO_TEXT); 101 102 if (dataObject->hasMarkup()) 103 gtk_target_list_add(list, gdkMarkupAtom, 0, WEBKIT_WEB_VIEW_TARGET_INFO_HTML); 104 105 return list; 106 } 107 108 static DataObjectGtk* settingClipboardDataObject = 0; 109 static gpointer settingClipboardData = 0; 110 static void getClipboardContentsCallback(GtkClipboard* clipboard, GtkSelectionData *selectionData, guint info, gpointer data) 111 { 112 DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard); 113 ASSERT(dataObject); 114 fillSelectionData(selectionData, info, dataObject); 115 } 116 117 static void clearClipboardContentsCallback(GtkClipboard* clipboard, gpointer data) 118 { 119 DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard); 120 ASSERT(dataObject); 121 122 // Only clear the DataObject for this clipboard if we are not currently setting it. 123 if (dataObject != settingClipboardDataObject) 124 dataObject->clear(); 125 126 // Only collapse the selection if this is an X11 primary clipboard 127 // and we aren't currently setting the clipboard for this WebView. 128 if (!data || data == settingClipboardData) 129 return; 130 131 WebKitWebView* webView = reinterpret_cast<WebKitWebView*>(data); 132 WebCore::Page* corePage = core(webView); 133 134 if (!corePage || !corePage->focusController()) { 135 g_object_unref(webView); 136 return; 137 } 138 139 Frame* frame = corePage->focusController()->focusedOrMainFrame(); 140 141 // Collapse the selection without clearing it 142 ASSERT(frame); 143 frame->selection()->setBase(frame->selection()->extent(), frame->selection()->affinity()); 144 145 g_object_unref(webView); 146 } 147 148 void PasteboardHelperGtk::writeClipboardContents(GtkClipboard* clipboard, gpointer data) 149 { 150 DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard); 151 GtkTargetList* list = targetListForDataObject(dataObject); 152 153 int numberOfTargets; 154 GtkTargetEntry* table = gtk_target_table_new_from_list(list, &numberOfTargets); 155 156 if (numberOfTargets > 0 && table) { 157 settingClipboardDataObject = dataObject; 158 settingClipboardData = data; 159 160 // Protect the web view from being destroyed before one of the clipboard callbacks 161 // is called. Balanced in both getClipboardContentsCallback and 162 // clearClipboardContentsCallback. 163 WebKitWebView* webView = static_cast<WebKitWebView*>(data); 164 g_object_ref(webView); 165 166 gboolean succeeded = gtk_clipboard_set_with_data(clipboard, table, numberOfTargets, 167 getClipboardContentsCallback, 168 clearClipboardContentsCallback, data); 169 if (!succeeded) 170 g_object_unref(webView); 171 172 settingClipboardDataObject = 0; 173 settingClipboardData = 0; 174 } else 175 gtk_clipboard_clear(clipboard); 176 177 if (table) 178 gtk_target_table_free(table, numberOfTargets); 179 180 gtk_target_list_unref(list); 181 } 182 183 } 184