summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/gtk/PasteboardHelper.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/gtk/PasteboardHelper.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/gtk/PasteboardHelper.cpp')
-rw-r--r--Source/WebCore/platform/gtk/PasteboardHelper.cpp315
1 files changed, 315 insertions, 0 deletions
diff --git a/Source/WebCore/platform/gtk/PasteboardHelper.cpp b/Source/WebCore/platform/gtk/PasteboardHelper.cpp
new file mode 100644
index 0000000..013789f
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PasteboardHelper.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2010 Martin Robinson <mrobinson@webkit.org>
+ * Copyright (C) Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#include "config.h"
+#include "PasteboardHelper.h"
+
+#include "Chrome.h"
+#include "DataObjectGtk.h"
+#include "Frame.h"
+#include "GtkVersioning.h"
+#include "Page.h"
+#include "Pasteboard.h"
+#include "TextResourceDecoder.h"
+#include <gtk/gtk.h>
+#include <wtf/gobject/GOwnPtr.h>
+
+namespace WebCore {
+
+static GdkAtom textPlainAtom;
+static GdkAtom markupAtom;
+static GdkAtom netscapeURLAtom;
+static GdkAtom uriListAtom;
+static String gMarkupPrefix;
+
+static void removeMarkupPrefix(String& markup)
+{
+
+ // The markup prefix is not harmful, but we remove it from the string anyway, so that
+ // we can have consistent results with other ports during the layout tests.
+ if (markup.startsWith(gMarkupPrefix))
+ markup.remove(0, gMarkupPrefix.length());
+}
+
+static void initGdkAtoms()
+{
+ static gboolean initialized = FALSE;
+
+ if (initialized)
+ return;
+
+ initialized = TRUE;
+
+ textPlainAtom = gdk_atom_intern("text/plain;charset=utf-8", FALSE);
+ markupAtom = gdk_atom_intern("text/html", FALSE);
+ netscapeURLAtom = gdk_atom_intern("_NETSCAPE_URL", FALSE);
+ uriListAtom = gdk_atom_intern("text/uri-list", FALSE);
+ gMarkupPrefix = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
+}
+
+PasteboardHelper::PasteboardHelper()
+ : m_targetList(gtk_target_list_new(0, 0))
+{
+ initGdkAtoms();
+}
+
+PasteboardHelper::~PasteboardHelper()
+{
+ gtk_target_list_unref(m_targetList);
+}
+
+void PasteboardHelper::initializeTargetList()
+{
+ gtk_target_list_add_text_targets(m_targetList, getIdForTargetType(TargetTypeText));
+ gtk_target_list_add(m_targetList, markupAtom, 0, getIdForTargetType(TargetTypeMarkup));
+ gtk_target_list_add_uri_targets(m_targetList, getIdForTargetType(TargetTypeURIList));
+ gtk_target_list_add(m_targetList, netscapeURLAtom, 0, getIdForTargetType(TargetTypeNetscapeURL));
+ gtk_target_list_add_image_targets(m_targetList, getIdForTargetType(TargetTypeImage), TRUE);
+}
+
+static inline GtkWidget* widgetFromFrame(Frame* frame)
+{
+ ASSERT(frame);
+ Page* page = frame->page();
+ ASSERT(page);
+ Chrome* chrome = page->chrome();
+ ASSERT(chrome);
+ PlatformPageClient client = chrome->platformPageClient();
+ ASSERT(client);
+ return client;
+}
+
+GtkClipboard* PasteboardHelper::getCurrentClipboard(Frame* frame)
+{
+ if (usePrimarySelectionClipboard(widgetFromFrame(frame)))
+ return getPrimarySelectionClipboard(frame);
+ return getClipboard(frame);
+}
+
+GtkClipboard* PasteboardHelper::getClipboard(Frame* frame) const
+{
+ return gtk_widget_get_clipboard(widgetFromFrame(frame), GDK_SELECTION_CLIPBOARD);
+}
+
+GtkClipboard* PasteboardHelper::getPrimarySelectionClipboard(Frame* frame) const
+{
+ return gtk_widget_get_clipboard(widgetFromFrame(frame), GDK_SELECTION_PRIMARY);
+}
+
+GtkTargetList* PasteboardHelper::targetList() const
+{
+ return m_targetList;
+}
+
+static String selectionDataToUTF8String(GtkSelectionData* data)
+{
+ // g_strndup guards against selection data that is not null-terminated.
+ GOwnPtr<gchar> markupString(g_strndup(reinterpret_cast<const char*>(gtk_selection_data_get_data(data)), gtk_selection_data_get_length(data)));
+ return String::fromUTF8(markupString.get());
+}
+
+void PasteboardHelper::getClipboardContents(GtkClipboard* clipboard)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ ASSERT(dataObject);
+
+ if (gtk_clipboard_wait_is_text_available(clipboard)) {
+ GOwnPtr<gchar> textData(gtk_clipboard_wait_for_text(clipboard));
+ if (textData)
+ dataObject->setText(String::fromUTF8(textData.get()));
+ }
+
+ if (gtk_clipboard_wait_is_target_available(clipboard, markupAtom)) {
+ if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, markupAtom)) {
+ String markup(selectionDataToUTF8String(data));
+ removeMarkupPrefix(markup);
+ dataObject->setMarkup(markup);
+ gtk_selection_data_free(data);
+ }
+ }
+
+ if (gtk_clipboard_wait_is_target_available(clipboard, uriListAtom)) {
+ if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, uriListAtom)) {
+ dataObject->setURIList(selectionDataToUTF8String(data));
+ gtk_selection_data_free(data);
+ }
+ }
+}
+
+void PasteboardHelper::fillSelectionData(GtkSelectionData* selectionData, guint info, DataObjectGtk* dataObject)
+{
+ if (info == getIdForTargetType(TargetTypeText))
+ gtk_selection_data_set_text(selectionData, dataObject->text().utf8().data(), -1);
+
+ else if (info == getIdForTargetType(TargetTypeMarkup)) {
+ // Some Linux applications refuse to accept pasted markup unless it is
+ // prefixed by a content-type meta tag.
+ CString markup = (gMarkupPrefix + dataObject->markup()).utf8();
+ gtk_selection_data_set(selectionData, markupAtom, 8,
+ reinterpret_cast<const guchar*>(markup.data()), markup.length() + 1);
+
+ } else if (info == getIdForTargetType(TargetTypeURIList)) {
+ CString uriList = dataObject->uriList().utf8();
+ gtk_selection_data_set(selectionData, uriListAtom, 8,
+ reinterpret_cast<const guchar*>(uriList.data()), uriList.length() + 1);
+
+ } else if (info == getIdForTargetType(TargetTypeNetscapeURL) && dataObject->hasURL()) {
+ String url(dataObject->url());
+ String result(url);
+ result.append("\n");
+
+ if (dataObject->hasText())
+ result.append(dataObject->text());
+ else
+ result.append(url);
+
+ GOwnPtr<gchar> resultData(g_strdup(result.utf8().data()));
+ gtk_selection_data_set(selectionData, netscapeURLAtom, 8,
+ reinterpret_cast<const guchar*>(resultData.get()), strlen(resultData.get()) + 1);
+
+ } else if (info == getIdForTargetType(TargetTypeImage))
+ gtk_selection_data_set_pixbuf(selectionData, dataObject->image());
+}
+
+GtkTargetList* PasteboardHelper::targetListForDataObject(DataObjectGtk* dataObject)
+{
+ GtkTargetList* list = gtk_target_list_new(0, 0);
+
+ if (dataObject->hasText())
+ gtk_target_list_add_text_targets(list, getIdForTargetType(TargetTypeText));
+
+ if (dataObject->hasMarkup())
+ gtk_target_list_add(list, markupAtom, 0, getIdForTargetType(TargetTypeMarkup));
+
+ if (dataObject->hasURIList()) {
+ gtk_target_list_add_uri_targets(list, getIdForTargetType(TargetTypeURIList));
+ gtk_target_list_add(list, netscapeURLAtom, 0, getIdForTargetType(TargetTypeNetscapeURL));
+ }
+
+ if (dataObject->hasImage())
+ gtk_target_list_add_image_targets(list, getIdForTargetType(TargetTypeImage), TRUE);
+
+ return list;
+}
+
+void PasteboardHelper::fillDataObjectFromDropData(GtkSelectionData* data, guint info, DataObjectGtk* dataObject)
+{
+ if (!gtk_selection_data_get_data(data))
+ return;
+
+ GdkAtom target = gtk_selection_data_get_target(data);
+ if (target == textPlainAtom)
+ dataObject->setText(selectionDataToUTF8String(data));
+ else if (target == markupAtom) {
+ String markup(selectionDataToUTF8String(data));
+ removeMarkupPrefix(markup);
+ dataObject->setMarkup(markup);
+ } else if (target == uriListAtom) {
+ dataObject->setURIList(selectionDataToUTF8String(data));
+ } else if (target == netscapeURLAtom) {
+ String urlWithLabel(selectionDataToUTF8String(data));
+ Vector<String> pieces;
+ urlWithLabel.split("\n", pieces);
+
+ // Give preference to text/uri-list here, as it can hold more
+ // than one URI but still take the label if there is one.
+ if (!dataObject->hasURIList())
+ dataObject->setURIList(pieces[0]);
+ if (pieces.size() > 1)
+ dataObject->setText(pieces[1]);
+ }
+}
+
+Vector<GdkAtom> PasteboardHelper::dropAtomsForContext(GtkWidget* widget, GdkDragContext* context)
+{
+ // Always search for these common atoms.
+ Vector<GdkAtom> dropAtoms;
+ dropAtoms.append(textPlainAtom);
+ dropAtoms.append(markupAtom);
+ dropAtoms.append(uriListAtom);
+ dropAtoms.append(netscapeURLAtom);
+
+ // For images, try to find the most applicable image type.
+ GRefPtr<GtkTargetList> list(gtk_target_list_new(0, 0));
+ gtk_target_list_add_image_targets(list.get(), getIdForTargetType(TargetTypeImage), TRUE);
+ GdkAtom atom = gtk_drag_dest_find_target(widget, context, list.get());
+ if (atom != GDK_NONE)
+ dropAtoms.append(atom);
+
+ return dropAtoms;
+}
+
+static DataObjectGtk* settingClipboardDataObject = 0;
+
+static void getClipboardContentsCallback(GtkClipboard* clipboard, GtkSelectionData *selectionData, guint info, gpointer data)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ ASSERT(dataObject);
+ Pasteboard::generalPasteboard()->helper()->fillSelectionData(selectionData, info, dataObject);
+}
+
+static void clearClipboardContentsCallback(GtkClipboard* clipboard, gpointer data)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ ASSERT(dataObject);
+
+ // Only clear the DataObject for this clipboard if we are not currently setting it.
+ if (dataObject != settingClipboardDataObject)
+ dataObject->clear();
+
+ if (!data)
+ return;
+
+ GClosure* callback = static_cast<GClosure*>(data);
+ GValue firstArgument = {0, {{0}}};
+ g_value_init(&firstArgument, G_TYPE_POINTER);
+ g_value_set_pointer(&firstArgument, clipboard);
+ g_closure_invoke(callback, 0, 1, &firstArgument, 0);
+ g_closure_unref(callback);
+}
+
+void PasteboardHelper::writeClipboardContents(GtkClipboard* clipboard, GClosure* callback)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ GtkTargetList* list = targetListForDataObject(dataObject);
+
+ int numberOfTargets;
+ GtkTargetEntry* table = gtk_target_table_new_from_list(list, &numberOfTargets);
+
+ if (numberOfTargets > 0 && table) {
+ settingClipboardDataObject = dataObject;
+
+ gtk_clipboard_set_with_data(clipboard, table, numberOfTargets,
+ getClipboardContentsCallback, clearClipboardContentsCallback, callback);
+ gtk_clipboard_set_can_store(clipboard, 0, 0);
+
+ settingClipboardDataObject = 0;
+
+ } else
+ gtk_clipboard_clear(clipboard);
+
+ if (table)
+ gtk_target_table_free(table, numberOfTargets);
+ gtk_target_list_unref(list);
+}
+
+}
+