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
3 // found in the LICENSE file.
5 #include "ui/base/dragdrop/gtk_dnd_util.h"
9 #include "base/logging.h"
10 #include "base/pickle.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "ui/base/clipboard/custom_data_helper.h"
19 const int kBitsPerByte = 8;
21 void AddTargetToList(GtkTargetList* targets, int target_code) {
22 switch (target_code) {
24 gtk_target_list_add_text_targets(targets, ui::TEXT_PLAIN);
27 case ui::TEXT_URI_LIST:
28 gtk_target_list_add_uri_targets(targets, ui::TEXT_URI_LIST);
33 targets, ui::GetAtomForTarget(ui::TEXT_HTML), 0, ui::TEXT_HTML);
36 case ui::NETSCAPE_URL:
37 gtk_target_list_add(targets,
38 ui::GetAtomForTarget(ui::NETSCAPE_URL), 0, ui::NETSCAPE_URL);
42 case ui::CHROME_BOOKMARK_ITEM:
43 case ui::CHROME_NAMED_URL:
44 gtk_target_list_add(targets, ui::GetAtomForTarget(target_code),
45 GTK_TARGET_SAME_APP, target_code);
48 case ui::DIRECT_SAVE_FILE:
49 gtk_target_list_add(targets,
50 ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE), 0, ui::DIRECT_SAVE_FILE);
54 gtk_target_list_add(targets,
55 ui::GetAtomForTarget(ui::CUSTOM_DATA), 0, ui::CUSTOM_DATA);
59 NOTREACHED() << " Unexpected target code: " << target_code;
65 GdkAtom GetAtomForTarget(int target) {
68 static const GdkAtom kTabAtom = gdk_atom_intern(
69 "application/x-chrome-tab", false);
73 static const GdkAtom kHtmlAtom = gdk_atom_intern(
77 case CHROME_BOOKMARK_ITEM:
78 static const GdkAtom kBookmarkAtom = gdk_atom_intern(
79 "application/x-chrome-bookmark-item", false);
83 static const GdkAtom kTextAtom= gdk_atom_intern(
84 "text/plain;charset=utf-8", false);
88 static const GdkAtom kUrisAtom = gdk_atom_intern(
89 "text/uri-list", false);
92 case CHROME_NAMED_URL:
93 static const GdkAtom kNamedUrl = gdk_atom_intern(
94 "application/x-chrome-named-url", false);
98 static const GdkAtom kNetscapeUrl = gdk_atom_intern(
99 "_NETSCAPE_URL", false);
102 case TEXT_PLAIN_NO_CHARSET:
103 static const GdkAtom kTextNoCharsetAtom = gdk_atom_intern(
104 "text/plain", false);
105 return kTextNoCharsetAtom;
107 case DIRECT_SAVE_FILE:
108 static const GdkAtom kXdsAtom = gdk_atom_intern(
109 "XdndDirectSave0", false);
113 static const GdkAtom kCustomData = gdk_atom_intern(
114 kMimeTypeWebCustomData, false);
124 GtkTargetList* GetTargetListFromCodeMask(int code_mask) {
125 GtkTargetList* targets = gtk_target_list_new(NULL, 0);
127 for (size_t i = 1; i < INVALID_TARGET; i = i << 1) {
128 if (i == CHROME_WEBDROP_FILE_CONTENTS)
132 AddTargetToList(targets, i);
138 void SetSourceTargetListFromCodeMask(GtkWidget* source, int code_mask) {
139 GtkTargetList* targets = GetTargetListFromCodeMask(code_mask);
140 gtk_drag_source_set_target_list(source, targets);
141 gtk_target_list_unref(targets);
144 void SetDestTargetList(GtkWidget* dest, const int* target_codes) {
145 GtkTargetList* targets = gtk_target_list_new(NULL, 0);
147 for (size_t i = 0; target_codes[i] != -1; ++i) {
148 AddTargetToList(targets, target_codes[i]);
151 gtk_drag_dest_set_target_list(dest, targets);
152 gtk_target_list_unref(targets);
155 void WriteURLWithName(GtkSelectionData* selection_data,
157 base::string16 title,
160 // We prefer to not have empty titles. Set it to the filename extracted
162 title = UTF8ToUTF16(url.ExtractFileName());
167 gtk_selection_data_set_text(selection_data, url.spec().c_str(),
168 url.spec().length());
171 case TEXT_URI_LIST: {
173 uri_array[0] = strdup(url.spec().c_str());
175 gtk_selection_data_set_uris(selection_data, uri_array);
179 case CHROME_NAMED_URL: {
181 pickle.WriteString(UTF16ToUTF8(title));
182 pickle.WriteString(url.spec());
183 gtk_selection_data_set(
185 GetAtomForTarget(ui::CHROME_NAMED_URL),
187 reinterpret_cast<const guchar*>(pickle.data()),
192 // _NETSCAPE_URL format is URL + \n + title.
193 std::string utf8_text = url.spec() + "\n" + UTF16ToUTF8(title);
194 gtk_selection_data_set(selection_data,
195 gtk_selection_data_get_target(selection_data),
197 reinterpret_cast<const guchar*>(utf8_text.c_str()),
209 bool ExtractNamedURL(GtkSelectionData* selection_data,
211 base::string16* title) {
212 if (!selection_data || gtk_selection_data_get_length(selection_data) <= 0)
216 reinterpret_cast<const char*>(
217 gtk_selection_data_get_data(selection_data)),
218 gtk_selection_data_get_length(selection_data));
219 PickleIterator iter(data);
220 std::string title_utf8, url_utf8;
221 if (!data.ReadString(&iter, &title_utf8) ||
222 !data.ReadString(&iter, &url_utf8)) {
227 if (!gurl.is_valid())
231 *title = UTF8ToUTF16(title_utf8);
235 bool ExtractURIList(GtkSelectionData* selection_data, std::vector<GURL>* urls) {
236 gchar** uris = gtk_selection_data_get_uris(selection_data);
240 for (size_t i = 0; uris[i] != NULL; ++i) {
243 urls->push_back(url);
250 bool ExtractNetscapeURL(GtkSelectionData* selection_data,
252 base::string16* title) {
253 if (!selection_data || gtk_selection_data_get_length(selection_data) <= 0)
256 // Find the first '\n' in the data. It is the separator between the url and
259 reinterpret_cast<const char*>(
260 gtk_selection_data_get_data(selection_data)),
261 gtk_selection_data_get_length(selection_data));
262 std::string::size_type newline = data.find('\n');
263 if (newline == std::string::npos)
266 GURL gurl(data.substr(0, newline));
267 if (!gurl.is_valid())
271 *title = UTF8ToUTF16(data.substr(newline + 1));