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

Side by Side Diff: base/clipboard_linux.cc

Issue 9154: Rewrote the clipboard API to be more concurrent. Added a helper class to make... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 1 month 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
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 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 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 "base/clipboard.h" 5 #include "base/clipboard.h"
6 #include "base/string_util.h" 6 #include "base/string_util.h"
7 7
8 #include <gtk/gtk.h> 8 #include <gtk/gtk.h>
9 #include <map> 9 #include <map>
10 #include <set> 10 #include <set>
(...skipping 14 matching lines...) Expand all
25 Clipboard::TargetMap* data_map = 25 Clipboard::TargetMap* data_map =
26 reinterpret_cast<Clipboard::TargetMap*>(user_data); 26 reinterpret_cast<Clipboard::TargetMap*>(user_data);
27 27
28 Clipboard::TargetMap::iterator iter = 28 Clipboard::TargetMap::iterator iter =
29 data_map->find(std::string(gdk_atom_name(selection_data->target))); 29 data_map->find(std::string(gdk_atom_name(selection_data->target)));
30 30
31 if (iter == data_map->end()) 31 if (iter == data_map->end())
32 return; 32 return;
33 33
34 gtk_selection_data_set(selection_data, selection_data->target, 8, 34 gtk_selection_data_set(selection_data, selection_data->target, 8,
35 iter->second.first, 35 reinterpret_cast<guchar*>(iter->second.first),
36 iter->second.second); 36 iter->second.second);
37 } 37 }
38 38
39 // GtkClipboardClearFunc callback. 39 // GtkClipboardClearFunc callback.
40 // GTK will call this when new data is set on the clipboard (whether or not we 40 // We are guaranteed this will be called exactly once for each call to
41 // retain ownership) or when gtk_clipboard_clear() is called. We don't do 41 // gtk_clipboard_set_with_data
42 // anything because we don't want to clear the clipboard_data_ map if we call
43 // set data several times in a row. Instead we manually clear the
44 // clipboard_data_ map on Clear() and on Clipboard destruction.
45 void ClearData(GtkClipboard* clipboard, 42 void ClearData(GtkClipboard* clipboard,
46 gpointer user_data) { 43 gpointer user_data) {
44 Clipboard::TargetMap* map =
45 reinterpret_cast<Clipboard::TargetMap*>(user_data);
46 std::set<char*> ptrs;
47
48 for (Clipboard::TargetMap::iterator iter = map->begin();
49 iter != map->end(); ++iter)
50 ptrs.insert(iter->second.first);
51
52 for (std::set<char*>::iterator iter = ptrs.begin();
53 iter != ptrs.end(); ++iter)
54 delete[] *iter;
55
56 delete map;
57 }
58
59 // Frees the pointers in the given map and clears the map.
60 // Does not double-free any pointers.
61 void FreeTargetMap(Clipboard::TargetMap map) {
62 std::set<char*> ptrs;
63
64 for (Clipboard::TargetMap::iterator iter = map.begin();
65 iter != map.end(); ++iter)
66 ptrs.insert(iter->second.first);
67
68 for (std::set<char*>::iterator iter = ptrs.begin();
69 iter != ptrs.end(); ++iter)
70 delete[] *iter;
71
72 map.clear();
47 } 73 }
48 74
49 } // namespace 75 } // namespace
50 76
51 Clipboard::Clipboard() { 77 Clipboard::Clipboard() {
52 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); 78 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
53 } 79 }
54 80
55 Clipboard::~Clipboard() { 81 Clipboard::~Clipboard() {
56 // TODO(estade): do we want to save clipboard data after we exit? 82 // TODO(estade): do we want to save clipboard data after we exit?
57 // gtk_clipboard_set_can_store and gtk_clipboard_store work 83 // gtk_clipboard_set_can_store and gtk_clipboard_store work
58 // but have strangely awful performance. 84 // but have strangely awful performance.
59 Clear();
60 } 85 }
61 86
62 void Clipboard::Clear() { 87 void Clipboard::WriteObjects(const ObjectMap& objects) {
63 gtk_clipboard_clear(clipboard_); 88 clipboard_data_ = new TargetMap();
64 FreeTargetMap();
65 }
66 89
67 void Clipboard::WriteText(const std::wstring& text) { 90 for (ObjectMap::const_iterator iter = objects.begin();
68 std::string utf8_text = WideToUTF8(text); 91 iter != objects.end(); ++iter) {
69 size_t text_len = utf8_text.size() + 1; 92 DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
70 uint8* text_data = new uint8[text_len]; 93 }
71 memcpy(text_data, utf8_text.c_str(), text_len);
72
73 uint8* old_data = InsertOrOverwrite(kMimeText, text_data, text_len);
74 InsertOrOverwrite("TEXT", text_data, text_len);
75 InsertOrOverwrite("STRING", text_data, text_len);
76 InsertOrOverwrite("UTF8_STRING", text_data, text_len);
77 InsertOrOverwrite("COMPOUND_TEXT", text_data, text_len);
78
79 if (old_data)
80 delete[] old_data;
81
82 SetGtkClipboard();
83 }
84
85 void Clipboard::WriteHTML(const std::wstring& markup,
86 const std::string& src_url) {
87 // TODO(estade): might not want to ignore src_url
88 std::string html = WideToUTF8(markup);
89 size_t data_len = html.size() + 1;
90 uint8* html_data = new uint8[data_len];
91 memcpy(html_data, html.c_str(), data_len);
92
93 uint8* old_data = InsertOrOverwrite(kMimeHtml, html_data, data_len);
94
95 if (old_data)
96 delete[] old_data;
97 94
98 SetGtkClipboard(); 95 SetGtkClipboard();
99 } 96 }
100 97
98 // Take ownership of the GTK clipboard and inform it of the targets we support.
99 void Clipboard::SetGtkClipboard() {
100 GtkTargetEntry targets[clipboard_data_->size()];
101
102 int i = 0;
103 for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin();
104 iter != clipboard_data_->end(); ++iter, ++i) {
105 char* target_string = new char[iter->first.size() + 1];
106 strcpy(target_string, iter->first.c_str());
107 targets[i].target = target_string;
108 targets[i].flags = 0;
109 targets[i].info = i;
110 }
111
112 gtk_clipboard_set_with_data(clipboard_, targets,
113 clipboard_data_->size(),
114 GetData, ClearData,
115 clipboard_data_);
116
117 for (size_t i = 0; i < clipboard_data_->size(); i++)
118 delete[] targets[i].target;
119 }
120
121 void Clipboard::WriteText(const char* text_data, size_t text_len) {
122 char* data = new char[text_len];
123 memcpy(data, text_data, text_len);
124
125 InsertMapping(kMimeText, data, text_len);
126 InsertMapping("TEXT", data, text_len);
127 InsertMapping("STRING", data, text_len);
128 InsertMapping("UTF8_STRING", data, text_len);
129 InsertMapping("COMPOUND_TEXT", data, text_len);
130 }
131
132 void Clipboard::WriteHTML(const char* markup_data,
133 size_t markup_len,
134 const char* url_data,
135 size_t url_len) {
136 // TODO(estade): might not want to ignore |url_data|
137 char* data = new char[markup_len];
138 memcpy(data, markup_data, markup_len);
139
140 InsertMapping(kMimeHtml, data, markup_len);
141 }
142
101 // We do not use gtk_clipboard_wait_is_target_available because of 143 // We do not use gtk_clipboard_wait_is_target_available because of
102 // a bug with the gtk clipboard. It caches the available targets 144 // a bug with the gtk clipboard. It caches the available targets
103 // and does not always refresh the cache when it is appropriate. 145 // and does not always refresh the cache when it is appropriate.
104 // TODO(estade): When gnome bug 557315 is resolved, change this function 146 // TODO(estade): When gnome bug 557315 is resolved, change this function
105 // to use gtk_clipboard_wait_is_target_available. Also, catch requests 147 // to use gtk_clipboard_wait_is_target_available. Also, catch requests
106 // for plain text and change them to gtk_clipboard_wait_is_text_available 148 // for plain text and change them to gtk_clipboard_wait_is_text_available
107 // (which checks for several standard text targets). 149 // (which checks for several standard text targets).
108 bool Clipboard::IsFormatAvailable(Clipboard::FormatType format) const { 150 bool Clipboard::IsFormatAvailable(Clipboard::FormatType format) const {
109 bool retval = false; 151 bool retval = false;
110 GdkAtom* targets = NULL; 152 GdkAtom* targets = NULL;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 // static 220 // static
179 Clipboard::FormatType Clipboard::GetPlainTextWFormatType() { 221 Clipboard::FormatType Clipboard::GetPlainTextWFormatType() {
180 return GetPlainTextFormatType(); 222 return GetPlainTextFormatType();
181 } 223 }
182 224
183 // static 225 // static
184 Clipboard::FormatType Clipboard::GetHtmlFormatType() { 226 Clipboard::FormatType Clipboard::GetHtmlFormatType() {
185 return gdk_atom_intern(kMimeHtml, false); 227 return gdk_atom_intern(kMimeHtml, false);
186 } 228 }
187 229
188 // Take ownership of the GTK clipboard and inform it of the targets we support. 230 // Insert the key/value pair in the clipboard_data structure. If
189 void Clipboard::SetGtkClipboard() { 231 // the mapping already exists, it frees the associated data. Don't worry
190 GtkTargetEntry targets[clipboard_data_.size()]; 232 // about double freeing because if the same key is inserted into the
233 // map twice, it must have come from different Write* functions and the
234 // data pointer cannot be the same.
235 void Clipboard::InsertMapping(const char* key,
236 char* data,
237 size_t data_len) {
238 TargetMap::iterator iter = clipboard_data_->find(key);
191 239
192 int i = 0; 240 if (iter != clipboard_data_->end())
193 for (Clipboard::TargetMap::iterator iter = clipboard_data_.begin(); 241 delete[] iter->second.first;
194 iter != clipboard_data_.end(); iter++, i++) {
195 char* target_string = new char[iter->first.size() + 1];
196 strcpy(target_string, iter->first.c_str());
197 targets[i].target = target_string;
198 targets[i].flags = 0;
199 targets[i].info = i;
200 }
201 242
202 gtk_clipboard_set_with_data(clipboard_, targets, 243 (*clipboard_data_)[key] = std::make_pair(data, data_len);
203 clipboard_data_.size(),
204 GetData, ClearData,
205 &clipboard_data_);
206
207 for (size_t i = 0; i < clipboard_data_.size(); i++)
208 delete[] targets[i].target;
209 } 244 }
210
211 // Free the pointers in the clipboard_data_ map and reset the map.
212 void Clipboard::FreeTargetMap() {
213 std::set<uint8*> ptrs;
214
215 for (Clipboard::TargetMap::iterator iter = clipboard_data_.begin();
216 iter != clipboard_data_.end(); iter++)
217 ptrs.insert(iter->second.first);
218
219 for (std::set<uint8*>::iterator iter = ptrs.begin();
220 iter != ptrs.end(); iter++)
221 delete[] *iter;
222
223 clipboard_data_.clear();
224 }
225
226 // Insert the key/value pair in the clipboard_data structure. Overwrite
227 // and any old value that might have had that key. If we overwrote something,
228 // return the pointer to that something. Otherwise return null.
229 uint8* Clipboard::InsertOrOverwrite(std::string key,
230 uint8* data, size_t data_len) {
231 std::pair<std::string, std::pair<uint8*, size_t> > mapping =
232 std::make_pair(key, std::make_pair(data, data_len));
233
234 Clipboard::TargetMap::iterator iter = clipboard_data_.find(key);
235 uint8* retval = NULL;
236
237 if (iter == clipboard_data_.end()) {
238 clipboard_data_.insert(mapping);
239 } else {
240 retval = iter->second.first;
241 iter->second = mapping.second;
242 }
243
244 return retval;
245 }
246
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