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"; | |
109 const char kMimeTypeBitmap[] = "image/bmp"; | 110 const char kMimeTypeBitmap[] = "image/bmp"; |
110 const char kMimeTypeMozillaURL[] = "text/x-moz-url"; | 111 const char kMimeTypeMozillaURL[] = "text/x-moz-url"; |
111 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; | 112 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data"; |
112 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; | 113 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste"; |
113 | 114 |
114 std::string GdkAtomToString(const GdkAtom& atom) { | 115 std::string GdkAtomToString(const GdkAtom& atom) { |
115 gchar* name = gdk_atom_name(atom); | 116 gchar* name = gdk_atom_name(atom); |
116 std::string rv(name); | 117 std::string rv(name); |
117 g_free(name); | 118 g_free(name); |
118 return rv; | 119 return rv; |
(...skipping 26 matching lines...) Expand all Loading... | |
145 gtk_selection_data_set(selection_data, | 146 gtk_selection_data_set(selection_data, |
146 gtk_selection_data_get_target(selection_data), 8, | 147 gtk_selection_data_get_target(selection_data), 8, |
147 reinterpret_cast<guchar*>(iter->second.first), | 148 reinterpret_cast<guchar*>(iter->second.first), |
148 iter->second.second); | 149 iter->second.second); |
149 } | 150 } |
150 } | 151 } |
151 | 152 |
152 // GtkClipboardClearFunc callback. | 153 // GtkClipboardClearFunc callback. |
153 // We are guaranteed this will be called exactly once for each call to | 154 // We are guaranteed this will be called exactly once for each call to |
154 // gtk_clipboard_set_with_data. | 155 // gtk_clipboard_set_with_data. |
155 void ClearData(GtkClipboard* clipboard, | 156 void ClearData(GtkClipboard* /*clipboard*/, |
156 gpointer user_data) { | 157 gpointer user_data) { |
157 Clipboard::TargetMap* map = | 158 Clipboard::TargetMap* map = |
158 reinterpret_cast<Clipboard::TargetMap*>(user_data); | 159 reinterpret_cast<Clipboard::TargetMap*>(user_data); |
159 // The same data may be inserted under multiple keys, so use a set to | 160 // The same data may be inserted under multiple keys, so use a set to |
160 // uniq them. | 161 // uniq them. |
161 std::set<char*> ptrs; | 162 std::set<char*> ptrs; |
162 | 163 |
163 for (Clipboard::TargetMap::iterator iter = map->begin(); | 164 for (Clipboard::TargetMap::iterator iter = map->begin(); |
164 iter != map->end(); ++iter) { | 165 iter != map->end(); ++iter) { |
165 if (iter->first == kMimeTypeBitmap) | 166 if (iter->first == kMimeTypeBitmap) |
166 g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first)); | 167 g_object_unref(reinterpret_cast<GdkPixbuf*>(iter->second.first)); |
167 else | 168 else |
168 ptrs.insert(iter->second.first); | 169 ptrs.insert(iter->second.first); |
169 } | 170 } |
170 | 171 |
171 for (std::set<char*>::iterator iter = ptrs.begin(); | 172 for (std::set<char*>::iterator iter = ptrs.begin(); |
172 iter != ptrs.end(); ++iter) { | 173 iter != ptrs.end(); ++iter) { |
173 delete[] *iter; | 174 delete[] *iter; |
174 } | 175 } |
175 | 176 |
176 delete map; | 177 delete map; |
177 } | 178 } |
178 | 179 |
180 // Sets the content of |clipboard|. |clipboard_data| is to be allocated by new. | |
181 // The ownership is transferred to the function. |clipboard_data| is destroyed | |
182 // inside upon failure. | |
battre
2013/02/12 12:50:59
I think the entire comment can be simplified to
//
vasilii
2013/02/12 15:58:32
The whole function is reverted...
| |
183 bool GtkClipboardSetWithData(GtkClipboard* clipboard, | |
184 Clipboard::TargetMap* clipboard_data) { | |
185 scoped_array<GtkTargetEntry> targets( | |
186 new GtkTargetEntry[clipboard_data->size()]); | |
187 | |
188 int i = 0; | |
189 for (Clipboard::TargetMap::iterator iter = clipboard_data->begin(); | |
190 iter != clipboard_data->end(); ++iter, ++i) { | |
battre
2013/02/12 12:50:59
nit: +1 space
vasilii
2013/02/12 15:58:32
Done.
| |
191 targets[i].target = const_cast<char*>(iter->first.c_str()); | |
192 targets[i].flags = 0; | |
193 targets[i].info = 0; | |
194 } | |
195 | |
196 if (gtk_clipboard_set_with_data(clipboard, targets.get(), | |
197 clipboard_data->size(), | |
198 GetData, ClearData, | |
199 clipboard_data)) { | |
200 gtk_clipboard_set_can_store(clipboard, | |
201 targets.get(), | |
202 clipboard_data->size()); | |
203 return true; | |
204 } | |
205 // We should clear data manually on failure. | |
206 ClearData(clipboard, clipboard_data); | |
207 return false; | |
208 } | |
209 | |
179 } // namespace | 210 } // namespace |
180 | 211 |
181 Clipboard::FormatType::FormatType() : data_(GDK_NONE) { | 212 Clipboard::FormatType::FormatType() : data_(GDK_NONE) { |
182 } | 213 } |
183 | 214 |
184 Clipboard::FormatType::FormatType(const std::string& format_string) | 215 Clipboard::FormatType::FormatType(const std::string& format_string) |
185 : data_(StringToGdkAtom(format_string)) { | 216 : data_(StringToGdkAtom(format_string)) { |
186 } | 217 } |
187 | 218 |
188 Clipboard::FormatType::FormatType(const GdkAtom& native_format) | 219 Clipboard::FormatType::FormatType(const GdkAtom& native_format) |
(...skipping 21 matching lines...) Expand all Loading... | |
210 DCHECK(CalledOnValidThread()); | 241 DCHECK(CalledOnValidThread()); |
211 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | 242 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); |
212 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); | 243 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
213 } | 244 } |
214 | 245 |
215 Clipboard::~Clipboard() { | 246 Clipboard::~Clipboard() { |
216 DCHECK(CalledOnValidThread()); | 247 DCHECK(CalledOnValidThread()); |
217 gtk_clipboard_store(clipboard_); | 248 gtk_clipboard_store(clipboard_); |
218 } | 249 } |
219 | 250 |
220 void Clipboard::WriteObjects(Buffer buffer, const ObjectMap& objects) { | 251 void Clipboard::WriteObjectsImpl(Buffer buffer, |
252 const ObjectMap& objects, | |
253 SourceTag tag) { | |
221 DCHECK(CalledOnValidThread()); | 254 DCHECK(CalledOnValidThread()); |
222 clipboard_data_ = new TargetMap(); | 255 clipboard_data_ = new TargetMap(); |
223 | 256 |
224 for (ObjectMap::const_iterator iter = objects.begin(); | 257 for (ObjectMap::const_iterator iter = objects.begin(); |
225 iter != objects.end(); ++iter) { | 258 iter != objects.end(); ++iter) { |
226 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); | 259 DispatchObject(static_cast<ObjectType>(iter->first), iter->second); |
227 } | 260 } |
261 WriteSourceTag(tag); | |
228 | 262 |
229 SetGtkClipboard(buffer); | 263 SetGtkClipboard(buffer, tag); |
dcheng
2013/02/11 22:58:21
I'd prefer not to pass tag explicitly here. It's a
vasilii
2013/02/12 15:58:32
Done.
| |
230 } | 264 } |
231 | 265 |
232 // Take ownership of the GTK clipboard and inform it of the targets we support. | 266 // Take ownership of the GTK clipboard and inform it of the targets we support. |
233 void Clipboard::SetGtkClipboard(Buffer buffer) { | 267 void Clipboard::SetGtkClipboard(Buffer buffer, SourceTag tag) { |
234 scoped_ptr<GtkTargetEntry[]> targets( | |
235 new GtkTargetEntry[clipboard_data_->size()]); | |
236 | |
237 int i = 0; | |
238 for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin(); | |
239 iter != clipboard_data_->end(); ++iter, ++i) { | |
240 targets[i].target = const_cast<char*>(iter->first.c_str()); | |
241 targets[i].flags = 0; | |
242 targets[i].info = 0; | |
243 } | |
244 | |
245 GtkClipboard *clipboard = LookupBackingClipboard(buffer); | 268 GtkClipboard *clipboard = LookupBackingClipboard(buffer); |
246 | 269 if (GtkClipboardSetWithData(clipboard, clipboard_data_)) |
battre
2013/02/12 12:50:59
please add {}
vasilii
2013/02/12 15:58:32
Done.
| |
247 if (gtk_clipboard_set_with_data(clipboard, targets.get(), | 270 if (buffer == BUFFER_STANDARD) { |
248 clipboard_data_->size(), | 271 Clipboard::TargetMap::iterator text_iter = clipboard_data_->find("TEXT"); |
249 GetData, ClearData, | 272 if (text_iter != clipboard_data_->end()) { |
250 clipboard_data_)) { | 273 // Copy text and SourceTag to the selection clipboard. |
251 gtk_clipboard_set_can_store(clipboard, | 274 clipboard_data_ = new TargetMap; |
dcheng
2013/02/11 22:58:21
I think this might be cleaner if you pull this log
vasilii
2013/02/12 15:58:32
Done.
| |
252 targets.get(), | 275 WriteText(text_iter->second.first, text_iter->second.second); |
253 clipboard_data_->size()); | 276 WriteSourceTag(tag); |
254 } | 277 GtkClipboardSetWithData(primary_selection_, clipboard_data_); |
255 | 278 } |
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 } | 279 } |
262 } | |
263 | 280 |
264 // clipboard_data_ now owned by the GtkClipboard. | 281 // clipboard_data_ now owned by the GtkClipboard. |
265 clipboard_data_ = NULL; | 282 clipboard_data_ = NULL; |
266 } | 283 } |
267 | 284 |
268 void Clipboard::WriteText(const char* text_data, size_t text_len) { | 285 void Clipboard::WriteText(const char* text_data, size_t text_len) { |
269 char* data = new char[text_len]; | 286 char* data = new char[text_len]; |
270 memcpy(data, text_data, text_len); | 287 memcpy(data, text_data, text_len); |
271 | 288 |
272 InsertMapping(kMimeTypeText, data, text_len); | 289 InsertMapping(kMimeTypeText, data, text_len); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
343 // We assume that certain mapping types are only written by trusted code. | 360 // We assume that certain mapping types are only written by trusted code. |
344 // Therefore we must upkeep their integrity. | 361 // Therefore we must upkeep their integrity. |
345 if (format.Equals(GetBitmapFormatType())) | 362 if (format.Equals(GetBitmapFormatType())) |
346 return; | 363 return; |
347 char* data = new char[data_len]; | 364 char* data = new char[data_len]; |
348 memcpy(data, data_data, data_len); | 365 memcpy(data, data_data, data_len); |
349 // TODO(dcheng): Maybe this map should use GdkAtoms... | 366 // TODO(dcheng): Maybe this map should use GdkAtoms... |
350 InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len); | 367 InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len); |
351 } | 368 } |
352 | 369 |
370 void Clipboard::WriteSourceTag(SourceTag tag) { | |
371 if (tag != SourceTag()) { | |
372 ObjectMapParam binary = SourceTag2Binary(tag); | |
373 WriteData(GetSourceTagFormatType(), &binary[0], binary.size()); | |
374 } | |
375 } | |
376 | |
353 // We do not use gtk_clipboard_wait_is_target_available because of | 377 // We do not use gtk_clipboard_wait_is_target_available because of |
354 // a bug with the gtk clipboard. It caches the available targets | 378 // a bug with the gtk clipboard. It caches the available targets |
355 // and does not always refresh the cache when it is appropriate. | 379 // and does not always refresh the cache when it is appropriate. |
356 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, | 380 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, |
357 Clipboard::Buffer buffer) const { | 381 Clipboard::Buffer buffer) const { |
358 DCHECK(CalledOnValidThread()); | 382 DCHECK(CalledOnValidThread()); |
359 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 383 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
360 if (clipboard == NULL) | 384 if (clipboard == NULL) |
361 return false; | 385 return false; |
362 | 386 |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 type, result); | 593 type, result); |
570 gtk_selection_data_free(data); | 594 gtk_selection_data_free(data); |
571 } | 595 } |
572 | 596 |
573 void Clipboard::ReadBookmark(string16* title, std::string* url) const { | 597 void Clipboard::ReadBookmark(string16* title, std::string* url) const { |
574 // TODO(estade): implement this. | 598 // TODO(estade): implement this. |
575 NOTIMPLEMENTED(); | 599 NOTIMPLEMENTED(); |
576 } | 600 } |
577 | 601 |
578 void Clipboard::ReadData(const FormatType& format, std::string* result) const { | 602 void Clipboard::ReadData(const FormatType& format, std::string* result) const { |
603 ReadDataImpl(BUFFER_STANDARD, format, result); | |
604 } | |
605 | |
606 void Clipboard::ReadDataImpl(Buffer buffer, | |
607 const FormatType& format, | |
608 std::string* result) const { | |
579 DCHECK(CalledOnValidThread()); | 609 DCHECK(CalledOnValidThread()); |
610 result->clear(); | |
611 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | |
580 GtkSelectionData* data = | 612 GtkSelectionData* data = |
581 gtk_clipboard_wait_for_contents(clipboard_, format.ToGdkAtom()); | 613 gtk_clipboard_wait_for_contents(clipboard, format.ToGdkAtom()); |
582 if (!data) | 614 if (!data) |
583 return; | 615 return; |
584 result->assign(reinterpret_cast<const char*>( | 616 result->assign(reinterpret_cast<const char*>( |
585 gtk_selection_data_get_data(data)), | 617 gtk_selection_data_get_data(data)), |
586 gtk_selection_data_get_length(data)); | 618 gtk_selection_data_get_length(data)); |
587 gtk_selection_data_free(data); | 619 gtk_selection_data_free(data); |
588 } | 620 } |
589 | 621 |
622 Clipboard::SourceTag Clipboard::ReadSourceTag(Buffer buffer) const { | |
623 std::string result; | |
624 ReadDataImpl(buffer, GetSourceTagFormatType(), &result); | |
625 return Binary2SourceTag(result); | |
626 } | |
627 | |
590 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { | 628 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { |
591 DCHECK(CalledOnValidThread()); | 629 DCHECK(CalledOnValidThread()); |
592 if (buffer == BUFFER_STANDARD) | 630 if (buffer == BUFFER_STANDARD) |
593 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); | 631 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); |
594 else | 632 else |
595 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); | 633 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); |
596 } | 634 } |
597 | 635 |
598 //static | 636 //static |
599 Clipboard::FormatType Clipboard::GetFormatType( | 637 Clipboard::FormatType Clipboard::GetFormatType( |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
652 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); | 690 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); |
653 return type; | 691 return type; |
654 } | 692 } |
655 | 693 |
656 // static | 694 // static |
657 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { | 695 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() { |
658 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); | 696 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData)); |
659 return type; | 697 return type; |
660 } | 698 } |
661 | 699 |
700 // static | |
701 const Clipboard::FormatType& Clipboard::GetSourceTagFormatType() { | |
702 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kSourceTagType)); | |
703 return type; | |
704 } | |
705 | |
662 void Clipboard::InsertMapping(const char* key, | 706 void Clipboard::InsertMapping(const char* key, |
663 char* data, | 707 char* data, |
664 size_t data_len) { | 708 size_t data_len) { |
665 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); | 709 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); |
666 (*clipboard_data_)[key] = std::make_pair(data, data_len); | 710 (*clipboard_data_)[key] = std::make_pair(data, data_len); |
667 } | 711 } |
668 | 712 |
669 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { | 713 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { |
670 switch (clipboard) { | 714 switch (clipboard) { |
671 case BUFFER_STANDARD: | 715 case BUFFER_STANDARD: |
672 return clipboard_; | 716 return clipboard_; |
673 case BUFFER_SELECTION: | 717 case BUFFER_SELECTION: |
674 return primary_selection_; | 718 return primary_selection_; |
675 default: | 719 default: |
676 NOTREACHED(); | 720 NOTREACHED(); |
677 return NULL; | 721 return NULL; |
678 } | 722 } |
679 } | 723 } |
680 | 724 |
681 } // namespace ui | 725 } // namespace ui |
OLD | NEW |