Home | History | Annotate | Download | only in WebCoreSupport
      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