| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 | |
| OLD | NEW |