Remove support for specifying version on command line.
[chromium-blink-merge.git] / ui / base / dragdrop / os_exchange_data_provider_aurax11.cc
blob20a684240e5a7ef74f07ba62d112b63aa6014b63
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/os_exchange_data_provider_aurax11.h"
7 #include "base/logging.h"
8 #include "base/memory/ref_counted_memory.h"
9 #include "base/message_loop/message_pump_x11.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "net/base/net_util.h"
13 #include "ui/base/clipboard/clipboard.h"
14 #include "ui/base/clipboard/scoped_clipboard_writer.h"
15 #include "ui/base/x/selection_utils.h"
16 #include "ui/base/x/x11_util.h"
18 // Note: the GetBlah() methods are used immediately by the
19 // web_contents_view_aura.cc:PrepareDropData(), while the omnibox is a
20 // little more discriminating and calls HasBlah() before trying to get the
21 // information.
23 namespace ui {
25 namespace {
27 const char kDndSelection[] = "XdndSelection";
29 const char* kAtomsToCache[] = {
30 kString,
31 kText,
32 kUtf8String,
33 kDndSelection,
34 Clipboard::kMimeTypeURIList,
35 kMimeTypeMozillaURL,
36 Clipboard::kMimeTypeText,
37 NULL
40 } // namespace
42 OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11(
43 ::Window x_window,
44 const SelectionFormatMap& selection)
45 : x_display_(gfx::GetXDisplay()),
46 x_root_window_(DefaultRootWindow(x_display_)),
47 own_window_(false),
48 x_window_(x_window),
49 atom_cache_(x_display_, kAtomsToCache),
50 format_map_(selection),
51 selection_owner_(x_display_, x_window_,
52 atom_cache_.GetAtom(kDndSelection)) {
53 // We don't know all possible MIME types at compile time.
54 atom_cache_.allow_uncached_atoms();
57 OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11()
58 : x_display_(gfx::GetXDisplay()),
59 x_root_window_(DefaultRootWindow(x_display_)),
60 own_window_(true),
61 x_window_(XCreateWindow(
62 x_display_,
63 x_root_window_,
64 -100, -100, 10, 10, // x, y, width, height
65 0, // border width
66 CopyFromParent, // depth
67 InputOnly,
68 CopyFromParent, // visual
70 NULL)),
71 atom_cache_(x_display_, kAtomsToCache),
72 format_map_(),
73 selection_owner_(x_display_, x_window_,
74 atom_cache_.GetAtom(kDndSelection)) {
75 // We don't know all possible MIME types at compile time.
76 atom_cache_.allow_uncached_atoms();
78 XStoreName(x_display_, x_window_, "Chromium Drag & Drop Window");
80 base::MessagePumpX11::Current()->AddDispatcherForWindow(this, x_window_);
83 OSExchangeDataProviderAuraX11::~OSExchangeDataProviderAuraX11() {
84 if (own_window_) {
85 base::MessagePumpX11::Current()->RemoveDispatcherForWindow(x_window_);
86 XDestroyWindow(x_display_, x_window_);
90 void OSExchangeDataProviderAuraX11::TakeOwnershipOfSelection() const {
91 selection_owner_.TakeOwnershipOfSelection(format_map_);
94 void OSExchangeDataProviderAuraX11::RetrieveTargets(
95 std::vector<Atom>* targets) const {
96 selection_owner_.RetrieveTargets(targets);
99 SelectionFormatMap OSExchangeDataProviderAuraX11::GetFormatMap() const {
100 // We return the |selection_owner_|'s format map instead of our own in case
101 // ours has been modified since TakeOwnershipOfSelection() was called.
102 return selection_owner_.selection_format_map();
105 OSExchangeData::Provider* OSExchangeDataProviderAuraX11::Clone() const {
106 OSExchangeDataProviderAuraX11* ret = new OSExchangeDataProviderAuraX11();
107 ret->format_map_ = format_map_;
108 return ret;
111 void OSExchangeDataProviderAuraX11::SetString(const base::string16& text_data) {
112 std::string utf8 = base::UTF16ToUTF8(text_data);
113 scoped_refptr<base::RefCountedMemory> mem(
114 base::RefCountedString::TakeString(&utf8));
116 format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeText), mem);
117 format_map_.Insert(atom_cache_.GetAtom(kText), mem);
118 format_map_.Insert(atom_cache_.GetAtom(kString), mem);
119 format_map_.Insert(atom_cache_.GetAtom(kUtf8String), mem);
122 void OSExchangeDataProviderAuraX11::SetURL(const GURL& url,
123 const base::string16& title) {
124 // Mozilla's URL format: (UTF16: URL, newline, title)
125 if (url.is_valid()) {
126 base::string16 spec = base::UTF8ToUTF16(url.spec());
128 std::vector<unsigned char> data;
129 ui::AddString16ToVector(spec, &data);
130 ui::AddString16ToVector(base::ASCIIToUTF16("\n"), &data);
131 ui::AddString16ToVector(title, &data);
132 scoped_refptr<base::RefCountedMemory> mem(
133 base::RefCountedBytes::TakeVector(&data));
135 format_map_.Insert(atom_cache_.GetAtom(kMimeTypeMozillaURL), mem);
137 SetString(spec);
141 void OSExchangeDataProviderAuraX11::SetFilename(const base::FilePath& path) {
142 std::vector<OSExchangeData::FileInfo> data;
143 data.push_back(OSExchangeData::FileInfo(path, base::FilePath()));
144 SetFilenames(data);
147 void OSExchangeDataProviderAuraX11::SetFilenames(
148 const std::vector<OSExchangeData::FileInfo>& filenames) {
149 std::vector<std::string> paths;
150 for (std::vector<OSExchangeData::FileInfo>::const_iterator it =
151 filenames.begin(); it != filenames.end(); ++it) {
152 std::string url_spec = net::FilePathToFileURL(it->path).spec();
153 if (!url_spec.empty())
154 paths.push_back(url_spec);
157 std::string joined_data = JoinString(paths, '\n');
158 scoped_refptr<base::RefCountedMemory> mem(
159 base::RefCountedString::TakeString(&joined_data));
160 format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeURIList), mem);
163 void OSExchangeDataProviderAuraX11::SetPickledData(
164 const OSExchangeData::CustomFormat& format,
165 const Pickle& pickle) {
166 const unsigned char* data =
167 reinterpret_cast<const unsigned char*>(pickle.data());
169 std::vector<unsigned char> bytes;
170 bytes.insert(bytes.end(), data, data + pickle.size());
171 scoped_refptr<base::RefCountedMemory> mem(
172 base::RefCountedBytes::TakeVector(&bytes));
174 format_map_.Insert(atom_cache_.GetAtom(format.ToString().c_str()), mem);
177 bool OSExchangeDataProviderAuraX11::GetString(base::string16* result) const {
178 std::vector< ::Atom> text_atoms = ui::GetTextAtomsFrom(&atom_cache_);
179 std::vector< ::Atom> requested_types;
180 ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types);
182 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
183 if (data.IsValid()) {
184 std::string text = data.GetText();
185 *result = base::UTF8ToUTF16(text);
186 return true;
189 return false;
192 bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
193 GURL* url,
194 base::string16* title) const {
195 std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_);
196 std::vector< ::Atom> requested_types;
197 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
199 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
200 if (data.IsValid()) {
201 // TODO(erg): Technically, both of these forms can accept multiple URLs,
202 // but that doesn't match the assumptions of the rest of the system which
203 // expect single types.
205 if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) {
206 // Mozilla URLs are (UTF16: URL, newline, title).
207 base::string16 unparsed;
208 data.AssignTo(&unparsed);
210 std::vector<base::string16> tokens;
211 size_t num_tokens = Tokenize(unparsed, base::ASCIIToUTF16("\n"), &tokens);
212 if (num_tokens > 0) {
213 if (num_tokens > 1)
214 *title = tokens[1];
215 else
216 *title = base::string16();
218 *url = GURL(tokens[0]);
219 return true;
221 } else if (data.GetType() == atom_cache_.GetAtom(
222 Clipboard::kMimeTypeURIList)) {
223 std::vector<std::string> tokens = ui::ParseURIList(data);
224 for (std::vector<std::string>::const_iterator it = tokens.begin();
225 it != tokens.end(); ++it) {
226 GURL test_url(*it);
227 if (!test_url.SchemeIsFile()) {
228 *url = test_url;
229 *title = base::string16();
230 return true;
236 return false;
239 bool OSExchangeDataProviderAuraX11::GetFilename(base::FilePath* path) const {
240 std::vector<OSExchangeData::FileInfo> filenames;
241 if (GetFilenames(&filenames)) {
242 *path = filenames.front().path;
243 return true;
246 return false;
249 bool OSExchangeDataProviderAuraX11::GetFilenames(
250 std::vector<OSExchangeData::FileInfo>* filenames) const {
251 std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
252 std::vector< ::Atom> requested_types;
253 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
255 filenames->clear();
256 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
257 if (data.IsValid()) {
258 std::vector<std::string> tokens = ui::ParseURIList(data);
259 for (std::vector<std::string>::const_iterator it = tokens.begin();
260 it != tokens.end(); ++it) {
261 GURL url(*it);
262 base::FilePath file_path;
263 if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) {
264 filenames->push_back(OSExchangeData::FileInfo(file_path,
265 base::FilePath()));
270 return !filenames->empty();
273 bool OSExchangeDataProviderAuraX11::GetPickledData(
274 const OSExchangeData::CustomFormat& format,
275 Pickle* pickle) const {
276 std::vector< ::Atom> requested_types;
277 requested_types.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
279 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
280 if (data.IsValid()) {
281 // Note that the pickle object on the right hand side of the assignment
282 // only refers to the bytes in |data|. The assignment copies the data.
283 *pickle = Pickle(reinterpret_cast<const char*>(data.GetData()),
284 static_cast<int>(data.GetSize()));
285 return true;
288 return false;
291 bool OSExchangeDataProviderAuraX11::HasString() const {
292 std::vector< ::Atom> text_atoms = ui::GetTextAtomsFrom(&atom_cache_);
293 std::vector< ::Atom> requested_types;
294 ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types);
295 return !requested_types.empty();
298 bool OSExchangeDataProviderAuraX11::HasURL() const {
299 std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_);
300 std::vector< ::Atom> requested_types;
301 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
303 if (requested_types.empty())
304 return false;
306 // The Linux desktop doesn't differentiate between files and URLs like
307 // Windows does and stuffs all the data into one mime type.
308 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
309 if (data.IsValid()) {
310 if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) {
311 // File managers shouldn't be using this type, so this is a URL.
312 return true;
313 } else if (data.GetType() == atom_cache_.GetAtom(
314 ui::Clipboard::kMimeTypeURIList)) {
315 std::vector<std::string> tokens = ui::ParseURIList(data);
316 for (std::vector<std::string>::const_iterator it = tokens.begin();
317 it != tokens.end(); ++it) {
318 if (!GURL(*it).SchemeIsFile())
319 return true;
322 return false;
326 return false;
329 bool OSExchangeDataProviderAuraX11::HasFile() const {
330 std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
331 std::vector< ::Atom> requested_types;
332 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
334 if (requested_types.empty())
335 return false;
337 // To actually answer whether we have a file, we need to look through the
338 // contents of the kMimeTypeURIList type, and see if any of them are file://
339 // URIs.
340 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
341 if (data.IsValid()) {
342 std::vector<std::string> tokens = ui::ParseURIList(data);
343 for (std::vector<std::string>::const_iterator it = tokens.begin();
344 it != tokens.end(); ++it) {
345 GURL url(*it);
346 base::FilePath file_path;
347 if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path))
348 return true;
352 return false;
355 bool OSExchangeDataProviderAuraX11::HasCustomFormat(
356 const OSExchangeData::CustomFormat& format) const {
357 std::vector< ::Atom> url_atoms;
358 url_atoms.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
359 std::vector< ::Atom> requested_types;
360 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
362 return !requested_types.empty();
365 void OSExchangeDataProviderAuraX11::SetHtml(const base::string16& html,
366 const GURL& base_url) {
367 std::vector<unsigned char> bytes;
368 // Manually jam a UTF16 BOM into bytes because otherwise, other programs will
369 // assume UTF-8.
370 bytes.push_back(0xFF);
371 bytes.push_back(0xFE);
372 ui::AddString16ToVector(html, &bytes);
373 scoped_refptr<base::RefCountedMemory> mem(
374 base::RefCountedBytes::TakeVector(&bytes));
376 format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeHTML), mem);
379 bool OSExchangeDataProviderAuraX11::GetHtml(base::string16* html,
380 GURL* base_url) const {
381 std::vector< ::Atom> url_atoms;
382 url_atoms.push_back(atom_cache_.GetAtom(Clipboard::kMimeTypeHTML));
383 std::vector< ::Atom> requested_types;
384 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
386 ui::SelectionData data(format_map_.GetFirstOf(requested_types));
387 if (data.IsValid()) {
388 *html = data.GetHtml();
389 *base_url = GURL();
390 return true;
393 return false;
396 bool OSExchangeDataProviderAuraX11::HasHtml() const {
397 std::vector< ::Atom> url_atoms;
398 url_atoms.push_back(atom_cache_.GetAtom(Clipboard::kMimeTypeHTML));
399 std::vector< ::Atom> requested_types;
400 ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
402 return !requested_types.empty();
405 void OSExchangeDataProviderAuraX11::SetDragImage(
406 const gfx::ImageSkia& image,
407 const gfx::Vector2d& cursor_offset) {
408 drag_image_ = image;
409 drag_image_offset_ = cursor_offset;
412 const gfx::ImageSkia& OSExchangeDataProviderAuraX11::GetDragImage() const {
413 return drag_image_;
416 const gfx::Vector2d& OSExchangeDataProviderAuraX11::GetDragImageOffset() const {
417 return drag_image_offset_;
420 bool OSExchangeDataProviderAuraX11::Dispatch(const base::NativeEvent& event) {
421 XEvent* xev = event;
422 switch (xev->type) {
423 case SelectionRequest:
424 selection_owner_.OnSelectionRequest(xev->xselectionrequest);
425 break;
426 default:
427 NOTIMPLEMENTED();
430 return true;
433 bool OSExchangeDataProviderAuraX11::GetPlainTextURL(GURL* url) const {
434 base::string16 text;
435 if (GetString(&text)) {
436 GURL test_url(text);
437 if (test_url.is_valid()) {
438 *url = test_url;
439 return true;
443 return false;
446 std::vector< ::Atom> OSExchangeDataProviderAuraX11::GetTargets() const {
447 return format_map_.GetTypes();
450 ///////////////////////////////////////////////////////////////////////////////
451 // OSExchangeData, public:
453 // static
454 OSExchangeData::Provider* OSExchangeData::CreateProvider() {
455 return new OSExchangeDataProviderAuraX11();
458 } // namespace ui