OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "ui/base/clipboard/clipboard.h" | |
6 | |
7 #include <gtk/gtk.h> | |
8 #include <X11/extensions/Xfixes.h> | |
9 #include <X11/Xatom.h> | |
10 #include <map> | |
11 #include <set> | |
12 #include <string> | |
13 #include <utility> | |
14 | |
15 #include "base/basictypes.h" | |
16 #include "base/files/file_path.h" | |
17 #include "base/logging.h" | |
18 #include "base/memory/singleton.h" | |
19 #include "base/strings/utf_string_conversions.h" | |
20 #include "third_party/skia/include/core/SkBitmap.h" | |
21 #include "ui/base/clipboard/custom_data_helper.h" | |
22 #include "ui/base/gtk/gtk_signal.h" | |
23 #include "ui/base/x/x11_util.h" | |
24 #include "ui/gfx/canvas.h" | |
25 #include "ui/gfx/gtk_util.h" | |
26 #include "ui/gfx/scoped_gobject.h" | |
27 #include "ui/gfx/size.h" | |
28 | |
29 namespace ui { | |
30 | |
31 namespace { | |
32 | |
33 class SelectionChangeObserver { | |
34 public: | |
35 static SelectionChangeObserver* GetInstance(); | |
36 | |
37 uint64 clipboard_sequence_number() const { | |
38 return clipboard_sequence_number_; | |
39 } | |
40 uint64 primary_sequence_number() const { return primary_sequence_number_; } | |
41 | |
42 private: | |
43 friend struct DefaultSingletonTraits<SelectionChangeObserver>; | |
44 | |
45 SelectionChangeObserver(); | |
46 ~SelectionChangeObserver(); | |
47 | |
48 CHROMEG_CALLBACK_1(SelectionChangeObserver, GdkFilterReturn, OnXEvent, | |
49 GdkXEvent*, GdkEvent*); | |
50 | |
51 int event_base_; | |
52 Atom clipboard_atom_; | |
53 uint64 clipboard_sequence_number_; | |
54 uint64 primary_sequence_number_; | |
55 | |
56 DISALLOW_COPY_AND_ASSIGN(SelectionChangeObserver); | |
57 }; | |
58 | |
59 SelectionChangeObserver::SelectionChangeObserver() | |
60 : event_base_(-1), | |
61 clipboard_atom_(None), | |
62 clipboard_sequence_number_(0), | |
63 primary_sequence_number_(0) { | |
64 int ignored; | |
65 if (XFixesQueryExtension(gfx::GetXDisplay(), &event_base_, &ignored)) { | |
66 clipboard_atom_ = XInternAtom(gfx::GetXDisplay(), "CLIPBOARD", false); | |
67 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(), | |
68 clipboard_atom_, | |
69 XFixesSetSelectionOwnerNotifyMask | | |
70 XFixesSelectionWindowDestroyNotifyMask | | |
71 XFixesSelectionClientCloseNotifyMask); | |
72 // This seems to be semi-optional. For some reason, registering for any | |
73 // selection notify events seems to subscribe us to events for both the | |
74 // primary and the clipboard buffers. Register anyway just to be safe. | |
75 XFixesSelectSelectionInput(gfx::GetXDisplay(), GetX11RootWindow(), | |
76 XA_PRIMARY, | |
77 XFixesSetSelectionOwnerNotifyMask | | |
78 XFixesSelectionWindowDestroyNotifyMask | | |
79 XFixesSelectionClientCloseNotifyMask); | |
80 gdk_window_add_filter(NULL, &SelectionChangeObserver::OnXEventThunk, this); | |
81 } | |
82 } | |
83 | |
84 SelectionChangeObserver::~SelectionChangeObserver() { | |
85 } | |
86 | |
87 SelectionChangeObserver* SelectionChangeObserver::GetInstance() { | |
88 return Singleton<SelectionChangeObserver>::get(); | |
89 } | |
90 | |
91 GdkFilterReturn SelectionChangeObserver::OnXEvent(GdkXEvent* xevent, | |
92 GdkEvent* event) { | |
93 XEvent* xev = static_cast<XEvent*>(xevent); | |
94 | |
95 if (xev->type == event_base_ + XFixesSelectionNotify) { | |
96 XFixesSelectionNotifyEvent* ev = | |
97 reinterpret_cast<XFixesSelectionNotifyEvent*>(xev); | |
98 if (ev->selection == clipboard_atom_) { | |
99 clipboard_sequence_number_++; | |
100 } else if (ev->selection == XA_PRIMARY) { | |
101 primary_sequence_number_++; | |
102 } else { | |
103 DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; | |
104 } | |
105 } | |
106 return GDK_FILTER_CONTINUE; | |
107 } | |
108 | |
109 const char kMimeTypeBitmap[] = "image/bmp"; | |
110 const char kMimeTypeMozillaURL[] = "text/x-moz-url"; | |
111 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; | |
112 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; | |
113 | |
114 std::string GdkAtomToString(const GdkAtom& atom) { | |
115 gchar* name = gdk_atom_name(atom); | |
116 std::string rv(name); | |
117 g_free(name); | |
118 return rv; | |
119 } | |
120 | |
121 GdkAtom StringToGdkAtom(const std::string& str) { | |
122 return gdk_atom_intern(str.c_str(), FALSE); | |
123 } | |
124 | |
125 // GtkClipboardGetFunc callback. | |
126 // GTK will call this when an application wants data we copied to the clipboard. | |
127 void GetData(GtkClipboard* clipboard, | |
128 GtkSelectionData* selection_data, | |
129 guint info, | |
130 gpointer user_data) { | |
131 Clipboard::TargetMap* data_map = | |
132 reinterpret_cast<Clipboard::TargetMap*>(user_data); | |
133 | |
134 std::string target_string = GdkAtomToString( | |
135 gtk_selection_data_get_target(selection_data)); | |
136 Clipboard::TargetMap::iterator iter = data_map->find(target_string); | |
137 | |
138 if (iter == data_map->end()) | |
139 return; | |
140 | |
141 if (target_string == kMimeTypeBitmap) { | |
142 gtk_selection_data_set_pixbuf(selection_data, | |
143 reinterpret_cast<GdkPixbuf*>(iter->second.first)); | |
144 } else { | |
145 gtk_selection_data_set(selection_data, | |
146 gtk_selection_data_get_target(selection_data), 8, | |
147 reinterpret_cast<guchar*>(iter->second.first), | |
148 iter->second.second); | |
149 } | |
150 } | |
151 | |
152 // GtkClipboardClearFunc callback. | |
153 // We are guaranteed this will be called exactly once for each call to | |
154 // gtk_clipboard_set_with_data. | |
155 void ClearData(GtkClipboard* /*clipboard*/, | |
156 gpointer user_data) { | |
157 Clipboard::TargetMap* map = | |
158 reinterpret_cast<Clipboard::TargetMap*>(user_data); | |
159 // The same data may be inserted under multiple keys, so use a set to | |
160 // uniq them. | |
161 std::set<char*> ptrs; | |
162 | |
163 for (Clipboard::TargetMap::iterator iter = map->begin(); | |
164 iter != map->end(); ++iter) { | |
165 if (iter->first == kMimeTypeBitmap) | |
166 g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first)); | |
167 else | |
168 ptrs.insert(iter->second.first); | |
169 } | |
170 | |
171 for (std::set<char*>::iterator iter = ptrs.begin(); | |
172 iter != ptrs.end(); ++iter) { | |
173 delete[] *iter; | |
174 } | |
175 | |
176 delete map; | |
177 } | |
178 | |
179 } // namespace | |
180 | |
181 Clipboard::FormatType::FormatType() : data_(GDK_NONE) { | |
182 } | |
183 | |
184 Clipboard::FormatType::FormatType(const std::string& format_string) | |
185 : data_(StringToGdkAtom(format_string)) { | |
186 } | |
187 | |
188 Clipboard::FormatType::FormatType(const GdkAtom& native_format) | |
189 : data_(native_format) { | |
190 } | |
191 | |
192 Clipboard::FormatType::~FormatType() { | |
193 } | |
194 | |
195 std::string Clipboard::FormatType::Serialize() const { | |
196 return GdkAtomToString(data_); | |
197 } | |
198 | |
199 // static | |
200 Clipboard::FormatType Clipboard::FormatType::Deserialize( | |
201 const std::string& serialization) { | |
202 return FormatType(serialization); | |
203 } | |
204 | |
205 bool Clipboard::FormatType::Equals(const FormatType& other) const { | |
206 return data_ == other.data_; | |
207 } | |
208 | |
209 Clipboard::Clipboard() : clipboard_data_(NULL) { | |
210 DCHECK(CalledOnValidThread()); | |
211 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | |
212 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); | |
213 } | |
214 | |
215 Clipboard::~Clipboard() { | |
216 DCHECK(CalledOnValidThread()); | |
217 gtk_clipboard_store(clipboard_); | |
218 } | |
219 | |
220 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) { | |
221 DCHECK(CalledOnValidThread()); | |
222 clipboard_data_ = new TargetMap(); | |
223 | |
224 for (ObjectMap::const_iterator iter = objects.begin(); | |
225 iter != objects.end(); ++iter) { | |
226 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); | |
227 } | |
228 SetGtkClipboard(type); | |
229 | |
230 if (type == CLIPBOARD_TYPE_COPY_PASTE) { | |
231 ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT); | |
232 if (text_iter != objects.end()) { | |
233 // Copy text and SourceTag to the selection clipboard. | |
234 ObjectMap::const_iterator next_iter = text_iter; | |
235 WriteObjects(CLIPBOARD_TYPE_SELECTION, ObjectMap(text_iter, ++next_iter)); | |
236 } | |
237 } | |
238 } | |
239 | |
240 // Take ownership of the GTK clipboard and inform it of the targets we support. | |
241 void Clipboard::SetGtkClipboard(ClipboardType type) { | |
242 scoped_ptr<GtkTargetEntry[]> targets( | |
243 new GtkTargetEntry[clipboard_data_->size()]); | |
244 | |
245 int i = 0; | |
246 for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin(); | |
247 iter != clipboard_data_->end(); ++iter, ++i) { | |
248 targets[i].target = const_cast<char*>(iter->first.c_str()); | |
249 targets[i].flags = 0; | |
250 targets[i].info = 0; | |
251 } | |
252 | |
253 GtkClipboard *clipboard = LookupBackingClipboard(type); | |
254 | |
255 if (gtk_clipboard_set_with_data(clipboard, targets.get(), | |
256 clipboard_data_->size(), | |
257 GetData, ClearData, | |
258 clipboard_data_)) { | |
259 gtk_clipboard_set_can_store(clipboard, | |
260 targets.get(), | |
261 clipboard_data_->size()); | |
262 } | |
263 | |
264 // clipboard_data_ now owned by the GtkClipboard. | |
265 clipboard_data_ = NULL; | |
266 } | |
267 | |
268 void Clipboard::WriteText(const char* text_data, size_t text_len) { | |
269 char* data = new char[text_len]; | |
270 memcpy(data, text_data, text_len); | |
271 | |
272 InsertMapping(kMimeTypeText, data, text_len); | |
273 InsertMapping("TEXT", data, text_len); | |
274 InsertMapping("STRING", data, text_len); | |
275 InsertMapping("UTF8_STRING", data, text_len); | |
276 InsertMapping("COMPOUND_TEXT", data, text_len); | |
277 } | |
278 | |
279 void Clipboard::WriteHTML(const char* markup_data, | |
280 size_t markup_len, | |
281 const char* url_data, | |
282 size_t url_len) { | |
283 // TODO(estade): We need to expand relative links with |url_data|. | |
284 static const char* html_prefix = "<meta http-equiv=\"content-type\" " | |
285 "content=\"text/html; charset=utf-8\">"; | |
286 size_t html_prefix_len = strlen(html_prefix); | |
287 size_t total_len = html_prefix_len + markup_len + 1; | |
288 | |
289 char* data = new char[total_len]; | |
290 snprintf(data, total_len, "%s", html_prefix); | |
291 memcpy(data + html_prefix_len, markup_data, markup_len); | |
292 // Some programs expect NULL-terminated data. See http://crbug.com/42624 | |
293 data[total_len - 1] = '\0'; | |
294 | |
295 InsertMapping(kMimeTypeHTML, data, total_len); | |
296 } | |
297 | |
298 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) { | |
299 WriteData(GetRtfFormatType(), rtf_data, data_len); | |
300 } | |
301 | |
302 // Write an extra flavor that signifies WebKit was the last to modify the | |
303 // pasteboard. This flavor has no data. | |
304 void Clipboard::WriteWebSmartPaste() { | |
305 InsertMapping(kMimeTypeWebkitSmartPaste, NULL, 0); | |
306 } | |
307 | |
308 void Clipboard::WriteBitmap(const SkBitmap& bitmap) { | |
309 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap); | |
310 | |
311 // We store the GdkPixbuf*, and the size_t half of the pair is meaningless. | |
312 // Note that this contrasts with the vast majority of entries in our target | |
313 // map, which directly store the data and its length. | |
314 InsertMapping(kMimeTypeBitmap, reinterpret_cast<char*>(pixbuf), 0); | |
315 } | |
316 | |
317 void Clipboard::WriteBookmark(const char* title_data, size_t title_len, | |
318 const char* url_data, size_t url_len) { | |
319 // Write as a mozilla url (UTF16: URL, newline, title). | |
320 base::string16 url = base::UTF8ToUTF16(std::string(url_data, url_len) + "\n"); | |
321 base::string16 title = base::UTF8ToUTF16(std::string(title_data, title_len)); | |
322 if (title.length() >= std::numeric_limits<size_t>::max() / 4 || | |
323 url.length() >= std::numeric_limits<size_t>::max() / 4) | |
324 return; | |
325 size_t data_len = 2 * (title.length() + url.length()); | |
326 | |
327 char* data = new char[data_len]; | |
328 memcpy(data, url.data(), 2 * url.length()); | |
329 memcpy(data + 2 * url.length(), title.data(), 2 * title.length()); | |
330 InsertMapping(kMimeTypeMozillaURL, data, data_len); | |
331 } | |
332 | |
333 void Clipboard::WriteData(const FormatType& format, | |
334 const char* data_data, | |
335 size_t data_len) { | |
336 // We assume that certain mapping types are only written by trusted code. | |
337 // Therefore we must upkeep their integrity. | |
338 if (format.Equals(GetBitmapFormatType())) | |
339 return; | |
340 char* data = new char[data_len]; | |
341 memcpy(data, data_data, data_len); | |
342 // TODO(dcheng): Maybe this map should use GdkAtoms... | |
343 InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len); | |
344 } | |
345 | |
346 // We do not use gtk_clipboard_wait_is_target_available because of | |
347 // a bug with the gtk clipboard. It caches the available targets | |
348 // and does not always refresh the cache when it is appropriate. | |
349 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, | |
350 ClipboardType type) const { | |
351 DCHECK(CalledOnValidThread()); | |
352 GtkClipboard* clipboard = LookupBackingClipboard(type); | |
353 if (clipboard == NULL) | |
354 return false; | |
355 | |
356 bool retval = false; | |
357 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | |
358 clipboard, gdk_atom_intern_static_string("TARGETS")); | |
359 | |
360 bool format_is_plain_text = GetPlainTextFormatType().Equals(format); | |
361 if (format_is_plain_text) { | |
362 // This tries a number of common text targets. | |
363 if (data) { | |
364 retval = gtk_selection_data_targets_include_text(data); | |
365 } | |
366 // Some programs like Java decide to set an empty TARGETS list, so even if | |
367 // data is not NULL, we still have to fall back. | |
368 if (!retval) { | |
369 // Some programs post data to the clipboard without any targets. If this | |
370 // is the case we attempt to make sense of the contents as text. This is | |
371 // pretty unfortunate since it means we have to actually copy the data to | |
372 // see if it is available, but at least this path shouldn't be hit for | |
373 // conforming programs. | |
374 gchar* text = gtk_clipboard_wait_for_text(clipboard); | |
375 if (text) { | |
376 g_free(text); | |
377 retval = true; | |
378 } | |
379 } | |
380 } else if (data) { | |
381 GdkAtom* targets = NULL; | |
382 int num = 0; | |
383 gtk_selection_data_get_targets(data, &targets, &num); | |
384 | |
385 for (int i = 0; i < num; i++) { | |
386 if (targets[i] == format.ToGdkAtom()) { | |
387 retval = true; | |
388 break; | |
389 } | |
390 } | |
391 | |
392 g_free(targets); | |
393 } | |
394 | |
395 if (data) | |
396 gtk_selection_data_free(data); | |
397 | |
398 return retval; | |
399 } | |
400 | |
401 void Clipboard::Clear(ClipboardType type) { | |
402 DCHECK(CalledOnValidThread()); | |
403 GtkClipboard* clipboard = LookupBackingClipboard(type); | |
404 if (clipboard == NULL) | |
405 return; | |
406 gtk_clipboard_clear(clipboard); | |
407 } | |
408 | |
409 void Clipboard::ReadAvailableTypes(ClipboardType type, | |
410 std::vector<base::string16>* types, | |
411 bool* contains_filenames) const { | |
412 DCHECK(CalledOnValidThread()); | |
413 if (!types || !contains_filenames) { | |
414 NOTREACHED(); | |
415 return; | |
416 } | |
417 | |
418 types->clear(); | |
419 if (IsFormatAvailable(GetPlainTextFormatType(), type)) | |
420 types->push_back(base::UTF8ToUTF16(kMimeTypeText)); | |
421 if (IsFormatAvailable(GetHtmlFormatType(), type)) | |
422 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML)); | |
423 if (IsFormatAvailable(GetRtfFormatType(), type)) | |
424 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF)); | |
425 if (IsFormatAvailable(GetBitmapFormatType(), type)) | |
426 types->push_back(base::UTF8ToUTF16(kMimeTypePNG)); | |
427 *contains_filenames = false; | |
428 | |
429 GtkClipboard* clipboard = LookupBackingClipboard(type); | |
430 if (!clipboard) | |
431 return; | |
432 | |
433 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | |
434 clipboard, GetWebCustomDataFormatType().ToGdkAtom()); | |
435 if (!data) | |
436 return; | |
437 ReadCustomDataTypes(gtk_selection_data_get_data(data), | |
438 gtk_selection_data_get_length(data), | |
439 types); | |
440 gtk_selection_data_free(data); | |
441 } | |
442 | |
443 | |
444 void Clipboard::ReadText(ClipboardType type, base::string16* result) const { | |
445 DCHECK(CalledOnValidThread()); | |
446 GtkClipboard* clipboard = LookupBackingClipboard(type); | |
447 if (clipboard == NULL) | |
448 return; | |
449 | |
450 result->clear(); | |
451 gchar* text = gtk_clipboard_wait_for_text(clipboard); | |
452 | |
453 if (text == NULL) | |
454 return; | |
455 | |
456 // TODO(estade): do we want to handle the possible error here? | |
457 base::UTF8ToUTF16(text, strlen(text), result); | |
458 g_free(text); | |
459 } | |
460 | |
461 void Clipboard::ReadAsciiText(ClipboardType type, | |
462 std::string* result) const { | |
463 DCHECK(CalledOnValidThread()); | |
464 GtkClipboard* clipboard = LookupBackingClipboard(type); | |
465 if (clipboard == NULL) | |
466 return; | |
467 | |
468 result->clear(); | |
469 gchar* text = gtk_clipboard_wait_for_text(clipboard); | |
470 | |
471 if (text == NULL) | |
472 return; | |
473 | |
474 result->assign(text); | |
475 g_free(text); | |
476 } | |
477 | |
478 // TODO(estade): handle different charsets. | |
479 // TODO(port): set *src_url. | |
480 void Clipboard::ReadHTML(ClipboardType type, | |
481 base::string16* markup, | |
482 std::string* src_url, | |
483 uint32* fragment_start, | |
484 uint32* fragment_end) const { | |
485 DCHECK(CalledOnValidThread()); | |
486 markup->clear(); | |
487 if (src_url) | |
488 src_url->clear(); | |
489 *fragment_start = 0; | |
490 *fragment_end = 0; | |
491 | |
492 GtkClipboard* clipboard = LookupBackingClipboard(type); | |
493 if (clipboard == NULL) | |
494 return; | |
495 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, | |
496 GetHtmlFormatType().ToGdkAtom()); | |
497 | |
498 if (!data) | |
499 return; | |
500 | |
501 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | |
502 // UTF-16, otherwise assume UTF-8. | |
503 gint data_length = gtk_selection_data_get_length(data); | |
504 const guchar* raw_data = gtk_selection_data_get_data(data); | |
505 | |
506 if (data_length >= 2 && | |
507 reinterpret_cast<const uint16_t*>(raw_data)[0] == 0xFEFF) { | |
508 markup->assign(reinterpret_cast<const uint16_t*>(raw_data) + 1, | |
509 (data_length / 2) - 1); | |
510 } else { | |
511 base::UTF8ToUTF16( | |
512 reinterpret_cast<const char*>(raw_data), data_length, markup); | |
513 } | |
514 | |
515 // If there is a terminating NULL, drop it. | |
516 if (!markup->empty() && markup->at(markup->length() - 1) == '\0') | |
517 markup->resize(markup->length() - 1); | |
518 | |
519 *fragment_start = 0; | |
520 DCHECK(markup->length() <= kuint32max); | |
521 *fragment_end = static_cast<uint32>(markup->length()); | |
522 | |
523 gtk_selection_data_free(data); | |
524 } | |
525 | |
526 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const { | |
527 DCHECK(CalledOnValidThread()); | |
528 ReadData(GetRtfFormatType(), result); | |
529 } | |
530 | |
531 SkBitmap Clipboard::ReadImage(ClipboardType type) const { | |
532 DCHECK(CalledOnValidThread()); | |
533 ScopedGObject<GdkPixbuf>::Type pixbuf( | |
534 gtk_clipboard_wait_for_image(clipboard_)); | |
535 if (!pixbuf.get()) | |
536 return SkBitmap(); | |
537 | |
538 gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf.get()), | |
539 gdk_pixbuf_get_height(pixbuf.get())), | |
540 1.0f, false); | |
541 { | |
542 skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); | |
543 cairo_t* context = scoped_platform_paint.GetPlatformSurface(); | |
544 gdk_cairo_set_source_pixbuf(context, pixbuf.get(), 0.0, 0.0); | |
545 cairo_paint(context); | |
546 } | |
547 return canvas.ExtractImageRep().sk_bitmap(); | |
548 } | |
549 | |
550 void Clipboard::ReadCustomData(ClipboardType clipboard_type, | |
551 const base::string16& type, | |
552 base::string16* result) const { | |
553 DCHECK(CalledOnValidThread()); | |
554 GtkClipboard* clipboard = LookupBackingClipboard(clipboard_type); | |
555 if (!clipboard) | |
556 return; | |
557 | |
558 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | |
559 clipboard, GetWebCustomDataFormatType().ToGdkAtom()); | |
560 if (!data) | |
561 return; | |
562 ReadCustomDataForType(gtk_selection_data_get_data(data), | |
563 gtk_selection_data_get_length(data), | |
564 type, result); | |
565 gtk_selection_data_free(data); | |
566 } | |
567 | |
568 void Clipboard::ReadBookmark(base::string16* title, std::string* url) const { | |
569 // TODO(estade): implement this. | |
570 NOTIMPLEMENTED(); | |
571 } | |
572 | |
573 void Clipboard::ReadData(const FormatType& format, std::string* result) const { | |
574 DCHECK(CalledOnValidThread()); | |
575 result->clear(); | |
576 GtkSelectionData* data = | |
577 gtk_clipboard_wait_for_contents(clipboard_, format.ToGdkAtom()); | |
578 if (!data) | |
579 return; | |
580 result->assign(reinterpret_cast<const char*>( | |
581 gtk_selection_data_get_data(data)), | |
582 gtk_selection_data_get_length(data)); | |
583 gtk_selection_data_free(data); | |
584 } | |
585 | |
586 uint64 Clipboard::GetSequenceNumber(ClipboardType type) { | |
587 DCHECK(CalledOnValidThread()); | |
588 if (type == CLIPBOARD_TYPE_COPY_PASTE) | |
589 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); | |
590 else | |
591 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); | |
592 } | |
593 | |
594 //static | |
595 Clipboard::FormatType Clipboard::GetFormatType( | |
596 const std::string& format_string) { | |
597 return FormatType::Deserialize(format_string); | |
598 } | |
599 | |
600 // static | |
601 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { | |
602 CR_DEFINE_STATIC_LOCAL( | |
603 FormatType, type, (GDK_TARGET_STRING)); | |
604 return type; | |
605 } | |
606 | |
607 // static | |
608 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() { | |
609 return GetPlainTextFormatType(); | |
610 } | |
611 | |
612 // static | |
613 const Clipboard::FormatType& Clipboard::GetUrlFormatType() { | |
614 return GetPlainTextFormatType(); | |
615 } | |
616 | |
617 // static | |
618 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() { | |
619 return GetPlainTextWFormatType(); | |
620 } | |
621 | |
622 // static | |
623 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() { | |
624 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); | |
625 return type; | |
626 } | |
627 | |
628 // static | |
629 const Clipboard::FormatType& Clipboard::GetRtfFormatType() { | |
630 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF)); | |
631 return type; | |
632 } | |
633 | |
634 // static | |
635 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() { | |
636 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap)); | |
637 return type; | |
638 } | |
639 | |
640 // static | |
641 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() { | |
642 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); | |
643 return type; | |
644 } | |
645 | |
646 // static | |
647 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { | |
648 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); | |
649 return type; | |
650 } | |
651 | |
652 // static | |
653 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { | |
654 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); | |
655 return type; | |
656 } | |
657 | |
658 void Clipboard::InsertMapping(const char* key, | |
659 char* data, | |
660 size_t data_len) { | |
661 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); | |
662 (*clipboard_data_)[key] = std::make_pair(data, data_len); | |
663 } | |
664 | |
665 GtkClipboard* Clipboard::LookupBackingClipboard(ClipboardType type) const { | |
666 switch (type) { | |
667 case CLIPBOARD_TYPE_COPY_PASTE: | |
668 return clipboard_; | |
669 case CLIPBOARD_TYPE_SELECTION: | |
670 return primary_selection_; | |
671 default: | |
672 NOTREACHED(); | |
673 return NULL; | |
674 } | |
675 } | |
676 | |
677 } // namespace ui | |
OLD | NEW |