OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/base/clipboard/clipboard.h" | 5 #include "ui/base/clipboard/clipboard.h" |
6 | 6 |
7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
8 #include <X11/extensions/Xfixes.h> | 8 #include <X11/extensions/Xfixes.h> |
9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
10 #include <map> | 10 #include <map> |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 clipboard_sequence_number_++; | 99 clipboard_sequence_number_++; |
100 } else if (ev->selection == XA_PRIMARY) { | 100 } else if (ev->selection == XA_PRIMARY) { |
101 primary_sequence_number_++; | 101 primary_sequence_number_++; |
102 } else { | 102 } else { |
103 DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; | 103 DLOG(ERROR) << "Unexpected selection atom: " << ev->selection; |
104 } | 104 } |
105 } | 105 } |
106 return GDK_FILTER_CONTINUE; | 106 return GDK_FILTER_CONTINUE; |
107 } | 107 } |
108 | 108 |
109 const char kSourceTagType[] = "org.chromium.source-tag"; | |
110 const char kMimeTypeBitmap[] = "image/bmp"; | 109 const char kMimeTypeBitmap[] = "image/bmp"; |
111 const char kMimeTypeMozillaURL[] = "text/x-moz-url"; | 110 const char kMimeTypeMozillaURL[] = "text/x-moz-url"; |
112 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; | 111 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; |
113 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; | 112 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; |
114 | 113 |
115 std::string GdkAtomToString(const GdkAtom& atom) { | 114 std::string GdkAtomToString(const GdkAtom& atom) { |
116 gchar* name = gdk_atom_name(atom); | 115 gchar* name = gdk_atom_name(atom); |
117 std::string rv(name); | 116 std::string rv(name); |
118 g_free(name); | 117 g_free(name); |
119 return rv; | 118 return rv; |
(...skipping 26 matching lines...) Expand all Loading... |
146 gtk_selection_data_set(selection_data, | 145 gtk_selection_data_set(selection_data, |
147 gtk_selection_data_get_target(selection_data), 8, | 146 gtk_selection_data_get_target(selection_data), 8, |
148 reinterpret_cast<guchar*>(iter->second.first), | 147 reinterpret_cast<guchar*>(iter->second.first), |
149 iter->second.second); | 148 iter->second.second); |
150 } | 149 } |
151 } | 150 } |
152 | 151 |
153 // GtkClipboardClearFunc callback. | 152 // GtkClipboardClearFunc callback. |
154 // We are guaranteed this will be called exactly once for each call to | 153 // We are guaranteed this will be called exactly once for each call to |
155 // gtk_clipboard_set_with_data. | 154 // gtk_clipboard_set_with_data. |
156 void ClearData(GtkClipboard* /*clipboard*/, | 155 void ClearData(GtkClipboard* clipboard, |
157 gpointer user_data) { | 156 gpointer user_data) { |
158 Clipboard::TargetMap* map = | 157 Clipboard::TargetMap* map = |
159 reinterpret_cast<Clipboard::TargetMap*>(user_data); | 158 reinterpret_cast<Clipboard::TargetMap*>(user_data); |
160 // The same data may be inserted under multiple keys, so use a set to | 159 // The same data may be inserted under multiple keys, so use a set to |
161 // uniq them. | 160 // uniq them. |
162 std::set<char*> ptrs; | 161 std::set<char*> ptrs; |
163 | 162 |
164 for (Clipboard::TargetMap::iterator iter = map->begin(); | 163 for (Clipboard::TargetMap::iterator iter = map->begin(); |
165 iter != map->end(); ++iter) { | 164 iter != map->end(); ++iter) { |
166 if (iter->first == kMimeTypeBitmap) | 165 if (iter->first == kMimeTypeBitmap) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 DCHECK(CalledOnValidThread()); | 210 DCHECK(CalledOnValidThread()); |
212 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | 211 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); |
213 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); | 212 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
214 } | 213 } |
215 | 214 |
216 Clipboard::~Clipboard() { | 215 Clipboard::~Clipboard() { |
217 DCHECK(CalledOnValidThread()); | 216 DCHECK(CalledOnValidThread()); |
218 gtk_clipboard_store(clipboard_); | 217 gtk_clipboard_store(clipboard_); |
219 } | 218 } |
220 | 219 |
221 void Clipboard::WriteObjectsImpl(Buffer buffer, | 220 void Clipboard::WriteObjects(Buffer buffer, const ObjectMap& objects) { |
222 const ObjectMap& objects, | |
223 SourceTag tag) { | |
224 DCHECK(CalledOnValidThread()); | 221 DCHECK(CalledOnValidThread()); |
225 clipboard_data_ = new TargetMap(); | 222 clipboard_data_ = new TargetMap(); |
226 | 223 |
227 for (ObjectMap::const_iterator iter = objects.begin(); | 224 for (ObjectMap::const_iterator iter = objects.begin(); |
228 iter != objects.end(); ++iter) { | 225 iter != objects.end(); ++iter) { |
229 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); | 226 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); |
230 } | 227 } |
231 WriteSourceTag(tag); | 228 |
232 SetGtkClipboard(buffer); | 229 SetGtkClipboard(buffer); |
233 | |
234 if (buffer == BUFFER_STANDARD) { | |
235 ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT); | |
236 if (text_iter != objects.end()) { | |
237 // Copy text and SourceTag to the selection clipboard. | |
238 ObjectMap::const_iterator next_iter = text_iter; | |
239 WriteObjectsImpl(BUFFER_SELECTION, | |
240 ObjectMap(text_iter, ++next_iter), | |
241 tag); | |
242 } | |
243 } | |
244 } | 230 } |
245 | 231 |
246 // Take ownership of the GTK clipboard and inform it of the targets we support. | 232 // Take ownership of the GTK clipboard and inform it of the targets we support. |
247 void Clipboard::SetGtkClipboard(Buffer buffer) { | 233 void Clipboard::SetGtkClipboard(Buffer buffer) { |
248 scoped_array<GtkTargetEntry> targets( | 234 scoped_ptr<GtkTargetEntry[]> targets( |
249 new GtkTargetEntry[clipboard_data_->size()]); | 235 new GtkTargetEntry[clipboard_data_->size()]); |
250 | 236 |
251 int i = 0; | 237 int i = 0; |
252 for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin(); | 238 for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin(); |
253 iter != clipboard_data_->end(); ++iter, ++i) { | 239 iter != clipboard_data_->end(); ++iter, ++i) { |
254 targets[i].target = const_cast<char*>(iter->first.c_str()); | 240 targets[i].target = const_cast<char*>(iter->first.c_str()); |
255 targets[i].flags = 0; | 241 targets[i].flags = 0; |
256 targets[i].info = 0; | 242 targets[i].info = 0; |
257 } | 243 } |
258 | 244 |
259 GtkClipboard *clipboard = LookupBackingClipboard(buffer); | 245 GtkClipboard *clipboard = LookupBackingClipboard(buffer); |
260 | 246 |
261 if (gtk_clipboard_set_with_data(clipboard, targets.get(), | 247 if (gtk_clipboard_set_with_data(clipboard, targets.get(), |
262 clipboard_data_->size(), | 248 clipboard_data_->size(), |
263 GetData, ClearData, | 249 GetData, ClearData, |
264 clipboard_data_)) { | 250 clipboard_data_)) { |
265 gtk_clipboard_set_can_store(clipboard, | 251 gtk_clipboard_set_can_store(clipboard, |
266 targets.get(), | 252 targets.get(), |
267 clipboard_data_->size()); | 253 clipboard_data_->size()); |
268 } | 254 } |
269 | 255 |
| 256 if (buffer == BUFFER_STANDARD) { |
| 257 Clipboard::TargetMap::iterator text_iter = clipboard_data_->find("TEXT"); |
| 258 if (text_iter != clipboard_data_->end()) { |
| 259 gtk_clipboard_set_text(primary_selection_, text_iter->second.first, |
| 260 text_iter->second.second); |
| 261 } |
| 262 } |
| 263 |
270 // clipboard_data_ now owned by the GtkClipboard. | 264 // clipboard_data_ now owned by the GtkClipboard. |
271 clipboard_data_ = NULL; | 265 clipboard_data_ = NULL; |
272 } | 266 } |
273 | 267 |
274 void Clipboard::WriteText(const char* text_data, size_t text_len) { | 268 void Clipboard::WriteText(const char* text_data, size_t text_len) { |
275 char* data = new char[text_len]; | 269 char* data = new char[text_len]; |
276 memcpy(data, text_data, text_len); | 270 memcpy(data, text_data, text_len); |
277 | 271 |
278 InsertMapping(kMimeTypeText, data, text_len); | 272 InsertMapping(kMimeTypeText, data, text_len); |
279 InsertMapping("TEXT", data, text_len); | 273 InsertMapping("TEXT", data, text_len); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 // We assume that certain mapping types are only written by trusted code. | 343 // We assume that certain mapping types are only written by trusted code. |
350 // Therefore we must upkeep their integrity. | 344 // Therefore we must upkeep their integrity. |
351 if (format.Equals(GetBitmapFormatType())) | 345 if (format.Equals(GetBitmapFormatType())) |
352 return; | 346 return; |
353 char* data = new char[data_len]; | 347 char* data = new char[data_len]; |
354 memcpy(data, data_data, data_len); | 348 memcpy(data, data_data, data_len); |
355 // TODO(dcheng): Maybe this map should use GdkAtoms... | 349 // TODO(dcheng): Maybe this map should use GdkAtoms... |
356 InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len); | 350 InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len); |
357 } | 351 } |
358 | 352 |
359 void Clipboard::WriteSourceTag(SourceTag tag) { | |
360 if (tag != SourceTag()) { | |
361 ObjectMapParam binary = SourceTag2Binary(tag); | |
362 WriteData(GetSourceTagFormatType(), &binary[0], binary.size()); | |
363 } | |
364 } | |
365 | |
366 // We do not use gtk_clipboard_wait_is_target_available because of | 353 // We do not use gtk_clipboard_wait_is_target_available because of |
367 // a bug with the gtk clipboard. It caches the available targets | 354 // a bug with the gtk clipboard. It caches the available targets |
368 // and does not always refresh the cache when it is appropriate. | 355 // and does not always refresh the cache when it is appropriate. |
369 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, | 356 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, |
370 Clipboard::Buffer buffer) const { | 357 Clipboard::Buffer buffer) const { |
371 DCHECK(CalledOnValidThread()); | 358 DCHECK(CalledOnValidThread()); |
372 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 359 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
373 if (clipboard == NULL) | 360 if (clipboard == NULL) |
374 return false; | 361 return false; |
375 | 362 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 type, result); | 569 type, result); |
583 gtk_selection_data_free(data); | 570 gtk_selection_data_free(data); |
584 } | 571 } |
585 | 572 |
586 void Clipboard::ReadBookmark(string16* title, std::string* url) const { | 573 void Clipboard::ReadBookmark(string16* title, std::string* url) const { |
587 // TODO(estade): implement this. | 574 // TODO(estade): implement this. |
588 NOTIMPLEMENTED(); | 575 NOTIMPLEMENTED(); |
589 } | 576 } |
590 | 577 |
591 void Clipboard::ReadData(const FormatType& format, std::string* result) const { | 578 void Clipboard::ReadData(const FormatType& format, std::string* result) const { |
592 ReadDataImpl(BUFFER_STANDARD, format, result); | |
593 } | |
594 | |
595 void Clipboard::ReadDataImpl(Buffer buffer, | |
596 const FormatType& format, | |
597 std::string* result) const { | |
598 DCHECK(CalledOnValidThread()); | 579 DCHECK(CalledOnValidThread()); |
599 result->clear(); | |
600 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | |
601 GtkSelectionData* data = | 580 GtkSelectionData* data = |
602 gtk_clipboard_wait_for_contents(clipboard, format.ToGdkAtom()); | 581 gtk_clipboard_wait_for_contents(clipboard_, format.ToGdkAtom()); |
603 if (!data) | 582 if (!data) |
604 return; | 583 return; |
605 result->assign(reinterpret_cast<const char*>( | 584 result->assign(reinterpret_cast<const char*>( |
606 gtk_selection_data_get_data(data)), | 585 gtk_selection_data_get_data(data)), |
607 gtk_selection_data_get_length(data)); | 586 gtk_selection_data_get_length(data)); |
608 gtk_selection_data_free(data); | 587 gtk_selection_data_free(data); |
609 } | 588 } |
610 | 589 |
611 Clipboard::SourceTag Clipboard::ReadSourceTag(Buffer buffer) const { | |
612 std::string result; | |
613 ReadDataImpl(buffer, GetSourceTagFormatType(), &result); | |
614 return Binary2SourceTag(result); | |
615 } | |
616 | |
617 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { | 590 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { |
618 DCHECK(CalledOnValidThread()); | 591 DCHECK(CalledOnValidThread()); |
619 if (buffer == BUFFER_STANDARD) | 592 if (buffer == BUFFER_STANDARD) |
620 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); | 593 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); |
621 else | 594 else |
622 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); | 595 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); |
623 } | 596 } |
624 | 597 |
625 //static | 598 //static |
626 Clipboard::FormatType Clipboard::GetFormatType( | 599 Clipboard::FormatType Clipboard::GetFormatType( |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); | 652 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); |
680 return type; | 653 return type; |
681 } | 654 } |
682 | 655 |
683 // static | 656 // static |
684 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { | 657 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { |
685 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); | 658 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); |
686 return type; | 659 return type; |
687 } | 660 } |
688 | 661 |
689 // static | |
690 const Clipboard::FormatType& Clipboard::GetSourceTagFormatType() { | |
691 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kSourceTagType)); | |
692 return type; | |
693 } | |
694 | |
695 void Clipboard::InsertMapping(const char* key, | 662 void Clipboard::InsertMapping(const char* key, |
696 char* data, | 663 char* data, |
697 size_t data_len) { | 664 size_t data_len) { |
698 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); | 665 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); |
699 (*clipboard_data_)[key] = std::make_pair(data, data_len); | 666 (*clipboard_data_)[key] = std::make_pair(data, data_len); |
700 } | 667 } |
701 | 668 |
702 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { | 669 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { |
703 switch (clipboard) { | 670 switch (clipboard) { |
704 case BUFFER_STANDARD: | 671 case BUFFER_STANDARD: |
705 return clipboard_; | 672 return clipboard_; |
706 case BUFFER_SELECTION: | 673 case BUFFER_SELECTION: |
707 return primary_selection_; | 674 return primary_selection_; |
708 default: | 675 default: |
709 NOTREACHED(); | 676 NOTREACHED(); |
710 return NULL; | 677 return NULL; |
711 } | 678 } |
712 } | 679 } |
713 | 680 |
714 } // namespace ui | 681 } // namespace ui |
OLD | NEW |