1 /*
2 * Copyright (C) 2007 Luca Bruno <lethalman88@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
PasteboardHelperGtk()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
~PasteboardHelperGtk()44 PasteboardHelperGtk::~PasteboardHelperGtk()
45 {
46 gtk_target_list_unref(m_targetList);
47 }
48
getCurrentTarget(Frame * frame) const49 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
getClipboard(Frame * frame) const59 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
getPrimary(Frame * frame) const66 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
targetList() const73 GtkTargetList* PasteboardHelperGtk::targetList() const
74 {
75 return m_targetList;
76 }
77
getWebViewTargetInfoHtml() const78 gint PasteboardHelperGtk::getWebViewTargetInfoHtml() const
79 {
80 return WEBKIT_WEB_VIEW_TARGET_INFO_HTML;
81 }
82
fillSelectionData(GtkSelectionData * selectionData,guint info,DataObjectGtk * dataObject)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
targetListForDataObject(DataObjectGtk * dataObject)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;
getClipboardContentsCallback(GtkClipboard * clipboard,GtkSelectionData * selectionData,guint info,gpointer data)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
clearClipboardContentsCallback(GtkClipboard * clipboard,gpointer data)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
writeClipboardContents(GtkClipboard * clipboard,gpointer data)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