Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: base/clipboard_linux.cc

Issue 260003: Move the clipboard stuff out of base and into app/clipboard. I renamed... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/clipboard.cc ('k') | base/clipboard_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/clipboard.h"
6
7 #include <gtk/gtk.h>
8 #include <map>
9 #include <set>
10 #include <string>
11 #include <utility>
12
13 #include "base/file_path.h"
14 #include "base/gfx/size.h"
15 #include "base/scoped_ptr.h"
16 #include "base/linux_util.h"
17 #include "base/string_util.h"
18
19 namespace {
20
21 const char kMimeBmp[] = "image/bmp";
22 const char kMimeHtml[] = "text/html";
23 const char kMimeText[] = "text/plain";
24 const char kMimeURI[] = "text/uri-list";
25 const char kMimeWebkitSmartPaste[] = "chromium/x-webkit-paste";
26
27 std::string GdkAtomToString(const GdkAtom& atom) {
28 gchar* name = gdk_atom_name(atom);
29 std::string rv(name);
30 g_free(name);
31 return rv;
32 }
33
34 GdkAtom StringToGdkAtom(const std::string& str) {
35 return gdk_atom_intern(str.c_str(), false);
36 }
37
38 // GtkClipboardGetFunc callback.
39 // GTK will call this when an application wants data we copied to the clipboard.
40 void GetData(GtkClipboard* clipboard,
41 GtkSelectionData* selection_data,
42 guint info,
43 gpointer user_data) {
44 Clipboard::TargetMap* data_map =
45 reinterpret_cast<Clipboard::TargetMap*>(user_data);
46
47 std::string target_string = GdkAtomToString(selection_data->target);
48 Clipboard::TargetMap::iterator iter = data_map->find(target_string);
49
50 if (iter == data_map->end())
51 return;
52
53 if (target_string == kMimeBmp) {
54 gtk_selection_data_set_pixbuf(selection_data,
55 reinterpret_cast<GdkPixbuf*>(iter->second.first));
56 } else if (target_string == kMimeURI) {
57 gchar* uri_list[2];
58 uri_list[0] = reinterpret_cast<gchar*>(iter->second.first);
59 uri_list[1] = NULL;
60 gtk_selection_data_set_uris(selection_data, uri_list);
61 } else {
62 gtk_selection_data_set(selection_data, selection_data->target, 8,
63 reinterpret_cast<guchar*>(iter->second.first),
64 iter->second.second);
65 }
66 }
67
68 // GtkClipboardClearFunc callback.
69 // We are guaranteed this will be called exactly once for each call to
70 // gtk_clipboard_set_with_data
71 void ClearData(GtkClipboard* clipboard,
72 gpointer user_data) {
73 Clipboard::TargetMap* map =
74 reinterpret_cast<Clipboard::TargetMap*>(user_data);
75 std::set<char*> ptrs;
76
77 for (Clipboard::TargetMap::iterator iter = map->begin();
78 iter != map->end(); ++iter) {
79 if (iter->first == kMimeBmp)
80 g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first));
81 else
82 ptrs.insert(iter->second.first);
83 }
84
85 for (std::set<char*>::iterator iter = ptrs.begin();
86 iter != ptrs.end(); ++iter) {
87 delete[] *iter;
88 }
89
90 delete map;
91 }
92
93 // Called on GdkPixbuf destruction; see WriteBitmap().
94 void GdkPixbufFree(guchar* pixels, gpointer data) {
95 free(pixels);
96 }
97
98 } // namespace
99
100 Clipboard::Clipboard() {
101 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
102 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
103 }
104
105 Clipboard::~Clipboard() {
106 // TODO(estade): do we want to save clipboard data after we exit?
107 // gtk_clipboard_set_can_store and gtk_clipboard_store work
108 // but have strangely awful performance.
109 }
110
111 void Clipboard::WriteObjects(const ObjectMap& objects) {
112 clipboard_data_ = new TargetMap();
113
114 for (ObjectMap::const_iterator iter = objects.begin();
115 iter != objects.end(); ++iter) {
116 DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
117 }
118
119 SetGtkClipboard();
120 }
121
122 // When a URL is copied from a render view context menu (via "copy link
123 // location", for example), we additionally stick it in the X clipboard. This
124 // matches other linux browsers.
125 void Clipboard::DidWriteURL(const std::string& utf8_text) {
126 gtk_clipboard_set_text(primary_selection_, utf8_text.c_str(),
127 utf8_text.length());
128 }
129
130 // Take ownership of the GTK clipboard and inform it of the targets we support.
131 void Clipboard::SetGtkClipboard() {
132 scoped_array<GtkTargetEntry> targets(
133 new GtkTargetEntry[clipboard_data_->size()]);
134
135 int i = 0;
136 for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin();
137 iter != clipboard_data_->end(); ++iter, ++i) {
138 targets[i].target = static_cast<gchar*>(malloc(iter->first.size() + 1));
139 memcpy(targets[i].target, iter->first.data(), iter->first.size());
140 targets[i].target[iter->first.size()] = '\0';
141
142 targets[i].flags = 0;
143 targets[i].info = i;
144 }
145
146 gtk_clipboard_set_with_data(clipboard_, targets.get(),
147 clipboard_data_->size(),
148 GetData, ClearData,
149 clipboard_data_);
150
151 for (size_t i = 0; i < clipboard_data_->size(); i++)
152 free(targets[i].target);
153 }
154
155 void Clipboard::WriteText(const char* text_data, size_t text_len) {
156 char* data = new char[text_len];
157 memcpy(data, text_data, text_len);
158
159 InsertMapping(kMimeText, data, text_len);
160 InsertMapping("TEXT", data, text_len);
161 InsertMapping("STRING", data, text_len);
162 InsertMapping("UTF8_STRING", data, text_len);
163 InsertMapping("COMPOUND_TEXT", data, text_len);
164 }
165
166 void Clipboard::WriteHTML(const char* markup_data,
167 size_t markup_len,
168 const char* url_data,
169 size_t url_len) {
170 // TODO(estade): might not want to ignore |url_data|
171 char* data = new char[markup_len];
172 memcpy(data, markup_data, markup_len);
173
174 InsertMapping(kMimeHtml, data, markup_len);
175 }
176
177 // Write an extra flavor that signifies WebKit was the last to modify the
178 // pasteboard. This flavor has no data.
179 void Clipboard::WriteWebSmartPaste() {
180 InsertMapping(kMimeWebkitSmartPaste, NULL, 0);
181 }
182
183 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
184 const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data);
185
186 guchar* data = base::BGRAToRGBA(reinterpret_cast<const uint8_t*>(pixel_data),
187 size->width(), size->height(), 0);
188
189 GdkPixbuf* pixbuf =
190 gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE,
191 8, size->width(), size->height(),
192 size->width() * 4, GdkPixbufFree, NULL);
193 // We store the GdkPixbuf*, and the size_t half of the pair is meaningless.
194 // Note that this contrasts with the vast majority of entries in our target
195 // map, which directly store the data and its length.
196 InsertMapping(kMimeBmp, reinterpret_cast<char*>(pixbuf), 0);
197 }
198
199 void Clipboard::WriteBookmark(const char* title_data, size_t title_len,
200 const char* url_data, size_t url_len) {
201 // Write as plain text.
202 WriteText(url_data, url_len);
203
204 // Write as a URI.
205 char* data = new char[url_len + 1];
206 memcpy(data, url_data, url_len);
207 data[url_len] = NULL;
208 InsertMapping(kMimeURI, data, url_len + 1);
209 }
210
211 void Clipboard::WriteFiles(const char* file_data, size_t file_len) {
212 NOTIMPLEMENTED();
213 }
214
215 void Clipboard::WriteData(const char* format_name, size_t format_len,
216 const char* data_data, size_t data_len) {
217 char* data = new char[data_len];
218 memcpy(data, data_data, data_len);
219 std::string format(format_name, format_len);
220 InsertMapping(format.c_str(), data, data_len);
221 }
222
223 // We do not use gtk_clipboard_wait_is_target_available because of
224 // a bug with the gtk clipboard. It caches the available targets
225 // and does not always refresh the cache when it is appropriate.
226 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format,
227 Clipboard::Buffer buffer) const {
228 GtkClipboard* clipboard = LookupBackingClipboard(buffer);
229 if (clipboard == NULL)
230 return false;
231
232 bool format_is_plain_text = GetPlainTextFormatType() == format;
233 if (format_is_plain_text) {
234 // This tries a number of common text targets.
235 if (gtk_clipboard_wait_is_text_available(clipboard))
236 return true;
237 }
238
239 bool retval = false;
240 GdkAtom* targets = NULL;
241 GtkSelectionData* data =
242 gtk_clipboard_wait_for_contents(clipboard,
243 gdk_atom_intern("TARGETS", false));
244
245 if (!data)
246 return false;
247
248 int num = 0;
249 gtk_selection_data_get_targets(data, &targets, &num);
250
251 // Some programs post data to the clipboard without any targets. If this is
252 // the case we attempt to make sense of the contents as text. This is pretty
253 // unfortunate since it means we have to actually copy the data to see if it
254 // is available, but at least this path shouldn't be hit for conforming
255 // programs.
256 if (num <= 0) {
257 if (format_is_plain_text) {
258 gchar* text = gtk_clipboard_wait_for_text(clipboard);
259 if (text) {
260 g_free(text);
261 retval = true;
262 }
263 }
264 }
265
266 GdkAtom format_atom = StringToGdkAtom(format);
267
268 for (int i = 0; i < num; i++) {
269 if (targets[i] == format_atom) {
270 retval = true;
271 break;
272 }
273 }
274
275 g_free(targets);
276 gtk_selection_data_free(data);
277
278 return retval;
279 }
280
281 bool Clipboard::IsFormatAvailableByString(const std::string& format,
282 Clipboard::Buffer buffer) const {
283 return IsFormatAvailable(format, buffer);
284 }
285
286 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const {
287 GtkClipboard* clipboard = LookupBackingClipboard(buffer);
288 if (clipboard == NULL)
289 return;
290
291 result->clear();
292 gchar* text = gtk_clipboard_wait_for_text(clipboard);
293
294 if (text == NULL)
295 return;
296
297 // TODO(estade): do we want to handle the possible error here?
298 UTF8ToUTF16(text, strlen(text), result);
299 g_free(text);
300 }
301
302 void Clipboard::ReadAsciiText(Clipboard::Buffer buffer,
303 std::string* result) const {
304 GtkClipboard* clipboard = LookupBackingClipboard(buffer);
305 if (clipboard == NULL)
306 return;
307
308 result->clear();
309 gchar* text = gtk_clipboard_wait_for_text(clipboard);
310
311 if (text == NULL)
312 return;
313
314 result->assign(text);
315 g_free(text);
316 }
317
318 void Clipboard::ReadFile(FilePath* file) const {
319 *file = FilePath();
320 }
321
322 // TODO(estade): handle different charsets.
323 // TODO(port): set *src_url.
324 void Clipboard::ReadHTML(Clipboard::Buffer buffer, string16* markup,
325 std::string* src_url) const {
326 GtkClipboard* clipboard = LookupBackingClipboard(buffer);
327 if (clipboard == NULL)
328 return;
329 markup->clear();
330
331 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard,
332 StringToGdkAtom(GetHtmlFormatType()));
333
334 if (!data)
335 return;
336
337 UTF8ToUTF16(reinterpret_cast<char*>(data->data), data->length, markup);
338 gtk_selection_data_free(data);
339 }
340
341 void Clipboard::ReadBookmark(string16* title, std::string* url) const {
342 // TODO(estade): implement this.
343 }
344
345 void Clipboard::ReadData(const std::string& format, std::string* result) {
346 GtkSelectionData* data =
347 gtk_clipboard_wait_for_contents(clipboard_, StringToGdkAtom(format));
348 if (!data)
349 return;
350 result->assign(reinterpret_cast<char*>(data->data), data->length);
351 gtk_selection_data_free(data);
352 }
353
354 // static
355 Clipboard::FormatType Clipboard::GetPlainTextFormatType() {
356 return GdkAtomToString(GDK_TARGET_STRING);
357 }
358
359 // static
360 Clipboard::FormatType Clipboard::GetPlainTextWFormatType() {
361 return GetPlainTextFormatType();
362 }
363
364 // static
365 Clipboard::FormatType Clipboard::GetHtmlFormatType() {
366 return std::string(kMimeHtml);
367 }
368
369 // static
370 Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() {
371 return std::string(kMimeWebkitSmartPaste);
372 }
373
374 // Insert the key/value pair in the clipboard_data structure. If
375 // the mapping already exists, it frees the associated data. Don't worry
376 // about double freeing because if the same key is inserted into the
377 // map twice, it must have come from different Write* functions and the
378 // data pointer cannot be the same.
379 void Clipboard::InsertMapping(const char* key,
380 char* data,
381 size_t data_len) {
382 TargetMap::iterator iter = clipboard_data_->find(key);
383
384 if (iter != clipboard_data_->end()) {
385 if (strcmp(kMimeBmp, key) == 0)
386 g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first));
387 else
388 delete[] iter->second.first;
389 }
390
391 (*clipboard_data_)[key] = std::make_pair(data, data_len);
392 }
393
394 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const {
395 GtkClipboard* result;
396
397 switch (clipboard) {
398 case BUFFER_STANDARD:
399 result = clipboard_;
400 break;
401 case BUFFER_SELECTION:
402 result = primary_selection_;
403 break;
404 default:
405 NOTREACHED();
406 result = NULL;
407 break;
408 }
409 return result;
410 }
OLDNEW
« no previous file with comments | « base/clipboard.cc ('k') | base/clipboard_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698