Index: base/clipboard_linux.cc |
=================================================================== |
--- base/clipboard_linux.cc (revision 4189) |
+++ base/clipboard_linux.cc (working copy) |
@@ -32,20 +32,46 @@ |
return; |
gtk_selection_data_set(selection_data, selection_data->target, 8, |
- iter->second.first, |
+ reinterpret_cast<guchar*>(iter->second.first), |
iter->second.second); |
} |
// GtkClipboardClearFunc callback. |
-// GTK will call this when new data is set on the clipboard (whether or not we |
-// retain ownership) or when gtk_clipboard_clear() is called. We don't do |
-// anything because we don't want to clear the clipboard_data_ map if we call |
-// set data several times in a row. Instead we manually clear the |
-// clipboard_data_ map on Clear() and on Clipboard destruction. |
+// We are guaranteed this will be called exactly once for each call to |
+// gtk_clipboard_set_with_data |
void ClearData(GtkClipboard* clipboard, |
gpointer user_data) { |
+ Clipboard::TargetMap* map = |
+ reinterpret_cast<Clipboard::TargetMap*>(user_data); |
+ std::set<char*> ptrs; |
+ |
+ for (Clipboard::TargetMap::iterator iter = map->begin(); |
+ iter != map->end(); ++iter) |
+ ptrs.insert(iter->second.first); |
+ |
+ for (std::set<char*>::iterator iter = ptrs.begin(); |
+ iter != ptrs.end(); ++iter) |
+ delete[] *iter; |
+ |
+ delete map; |
} |
+// Frees the pointers in the given map and clears the map. |
+// Does not double-free any pointers. |
+void FreeTargetMap(Clipboard::TargetMap map) { |
+ std::set<char*> ptrs; |
+ |
+ for (Clipboard::TargetMap::iterator iter = map.begin(); |
+ iter != map.end(); ++iter) |
+ ptrs.insert(iter->second.first); |
+ |
+ for (std::set<char*>::iterator iter = ptrs.begin(); |
+ iter != ptrs.end(); ++iter) |
+ delete[] *iter; |
+ |
+ map.clear(); |
+} |
+ |
} // namespace |
Clipboard::Clipboard() { |
@@ -56,46 +82,62 @@ |
// TODO(estade): do we want to save clipboard data after we exit? |
// gtk_clipboard_set_can_store and gtk_clipboard_store work |
// but have strangely awful performance. |
- Clear(); |
} |
-void Clipboard::Clear() { |
- gtk_clipboard_clear(clipboard_); |
- FreeTargetMap(); |
+void Clipboard::WriteObjects(const ObjectMap& objects) { |
+ clipboard_data_ = new TargetMap(); |
+ |
+ for (ObjectMap::const_iterator iter = objects.begin(); |
+ iter != objects.end(); ++iter) { |
+ DispatchObject(static_cast<ObjectType>(iter->first), iter->second); |
+ } |
+ |
+ SetGtkClipboard(); |
} |
-void Clipboard::WriteText(const std::wstring& text) { |
- std::string utf8_text = WideToUTF8(text); |
- size_t text_len = utf8_text.size() + 1; |
- uint8* text_data = new uint8[text_len]; |
- memcpy(text_data, utf8_text.c_str(), text_len); |
+// Take ownership of the GTK clipboard and inform it of the targets we support. |
+void Clipboard::SetGtkClipboard() { |
+ GtkTargetEntry targets[clipboard_data_->size()]; |
- uint8* old_data = InsertOrOverwrite(kMimeText, text_data, text_len); |
- InsertOrOverwrite("TEXT", text_data, text_len); |
- InsertOrOverwrite("STRING", text_data, text_len); |
- InsertOrOverwrite("UTF8_STRING", text_data, text_len); |
- InsertOrOverwrite("COMPOUND_TEXT", text_data, text_len); |
+ int i = 0; |
+ for (Clipboard::TargetMap::iterator iter = clipboard_data_->begin(); |
+ iter != clipboard_data_->end(); ++iter, ++i) { |
+ char* target_string = new char[iter->first.size() + 1]; |
+ strcpy(target_string, iter->first.c_str()); |
+ targets[i].target = target_string; |
+ targets[i].flags = 0; |
+ targets[i].info = i; |
+ } |
- if (old_data) |
- delete[] old_data; |
- |
- SetGtkClipboard(); |
+ gtk_clipboard_set_with_data(clipboard_, targets, |
+ clipboard_data_->size(), |
+ GetData, ClearData, |
+ clipboard_data_); |
+ |
+ for (size_t i = 0; i < clipboard_data_->size(); i++) |
+ delete[] targets[i].target; |
} |
-void Clipboard::WriteHTML(const std::wstring& markup, |
- const std::string& src_url) { |
- // TODO(estade): might not want to ignore src_url |
- std::string html = WideToUTF8(markup); |
- size_t data_len = html.size() + 1; |
- uint8* html_data = new uint8[data_len]; |
- memcpy(html_data, html.c_str(), data_len); |
+void Clipboard::WriteText(const char* text_data, size_t text_len) { |
+ char* data = new char[text_len]; |
+ memcpy(data, text_data, text_len); |
- uint8* old_data = InsertOrOverwrite(kMimeHtml, html_data, data_len); |
+ InsertMapping(kMimeText, data, text_len); |
+ InsertMapping("TEXT", data, text_len); |
+ InsertMapping("STRING", data, text_len); |
+ InsertMapping("UTF8_STRING", data, text_len); |
+ InsertMapping("COMPOUND_TEXT", data, text_len); |
+} |
- if (old_data) |
- delete[] old_data; |
+void Clipboard::WriteHTML(const char* markup_data, |
+ size_t markup_len, |
+ const char* url_data, |
+ size_t url_len) { |
+ // TODO(estade): might not want to ignore |url_data| |
+ char* data = new char[markup_len]; |
+ memcpy(data, markup_data, markup_len); |
- SetGtkClipboard(); |
+ InsertMapping(kMimeHtml, data, markup_len); |
} |
// We do not use gtk_clipboard_wait_is_target_available because of |
@@ -185,62 +227,18 @@ |
return gdk_atom_intern(kMimeHtml, false); |
} |
-// Take ownership of the GTK clipboard and inform it of the targets we support. |
-void Clipboard::SetGtkClipboard() { |
- GtkTargetEntry targets[clipboard_data_.size()]; |
+// Insert the key/value pair in the clipboard_data structure. If |
+// the mapping already exists, it frees the associated data. Don't worry |
+// about double freeing because if the same key is inserted into the |
+// map twice, it must have come from different Write* functions and the |
+// data pointer cannot be the same. |
+void Clipboard::InsertMapping(const char* key, |
+ char* data, |
+ size_t data_len) { |
+ TargetMap::iterator iter = clipboard_data_->find(key); |
- int i = 0; |
- for (Clipboard::TargetMap::iterator iter = clipboard_data_.begin(); |
- iter != clipboard_data_.end(); iter++, i++) { |
- char* target_string = new char[iter->first.size() + 1]; |
- strcpy(target_string, iter->first.c_str()); |
- targets[i].target = target_string; |
- targets[i].flags = 0; |
- targets[i].info = i; |
- } |
+ if (iter != clipboard_data_->end()) |
+ delete[] iter->second.first; |
- gtk_clipboard_set_with_data(clipboard_, targets, |
- clipboard_data_.size(), |
- GetData, ClearData, |
- &clipboard_data_); |
- |
- for (size_t i = 0; i < clipboard_data_.size(); i++) |
- delete[] targets[i].target; |
+ (*clipboard_data_)[key] = std::make_pair(data, data_len); |
} |
- |
-// Free the pointers in the clipboard_data_ map and reset the map. |
-void Clipboard::FreeTargetMap() { |
- std::set<uint8*> ptrs; |
- |
- for (Clipboard::TargetMap::iterator iter = clipboard_data_.begin(); |
- iter != clipboard_data_.end(); iter++) |
- ptrs.insert(iter->second.first); |
- |
- for (std::set<uint8*>::iterator iter = ptrs.begin(); |
- iter != ptrs.end(); iter++) |
- delete[] *iter; |
- |
- clipboard_data_.clear(); |
-} |
- |
-// Insert the key/value pair in the clipboard_data structure. Overwrite |
-// and any old value that might have had that key. If we overwrote something, |
-// return the pointer to that something. Otherwise return null. |
-uint8* Clipboard::InsertOrOverwrite(std::string key, |
- uint8* data, size_t data_len) { |
- std::pair<std::string, std::pair<uint8*, size_t> > mapping = |
- std::make_pair(key, std::make_pair(data, data_len)); |
- |
- Clipboard::TargetMap::iterator iter = clipboard_data_.find(key); |
- uint8* retval = NULL; |
- |
- if (iter == clipboard_data_.end()) { |
- clipboard_data_.insert(mapping); |
- } else { |
- retval = iter->second.first; |
- iter->second = mapping.second; |
- } |
- |
- return retval; |
-} |
- |