172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/web_drag_dest_gtk.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
11201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/bookmarks/bookmark_node_data.h"
12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h"
14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/common/url_constants.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/dragdrop/gtk_dnd_util.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebDragOperation;
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebDragOperationNone;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace {
24731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
25731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Returns the bookmark target atom, based on the underlying toolkit.
26731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick//
27731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// For GTK, bookmark drag data is encoded as pickle and associated with
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// ui::CHROME_BOOKMARK_ITEM. See // bookmark_utils::WriteBookmarksToSelection()
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// for details.
30731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// For Views, bookmark drag data is encoded in the same format, and
31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// associated with a custom format. See BookmarkNodeData::Write() for
32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// details.
33731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickGdkAtom GetBookmarkTargetAtom() {
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#if defined(TOOLKIT_VIEWS)
35201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return BookmarkNodeData::GetBookmarkCustomFormat();
36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#else
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM);
38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#endif
39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}  // namespace
42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : tab_contents_(tab_contents),
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      widget_(widget),
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      context_(NULL),
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      method_factory_(this) {
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    NULL, 0,
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               GDK_ACTION_LINK |
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               GDK_ACTION_MOVE));
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget, "drag-motion",
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnDragMotionThunk), this);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget, "drag-leave",
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnDragLeaveThunk), this);
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget, "drag-drop",
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnDragDropThunk), this);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(widget, "drag-data-received",
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnDragDataReceivedThunk), this);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(tony): Need a drag-data-delete handler for moving content out of
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the tab contents.  http://crbug.com/38989
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  destroy_handler_ = g_signal_connect(
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebDragDestGtk::~WebDragDestGtk() {
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (widget_) {
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_drag_dest_unset(widget_);
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    g_signal_handler_disconnect(widget_, destroy_handler_);
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (context_) {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    is_drop_target_ = operation != WebDragOperationNone;
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gdk_drag_status(context_, gtk_util::WebDragOpToGdkDragAction(operation),
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    drag_over_time_);
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebDragDestGtk::DragLeave() {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_contents_->render_view_host()->DragTargetDragLeave();
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_contents_->GetBookmarkDragDelegate()) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_contents_->GetBookmarkDragDelegate()->OnDragLeave(bookmark_drag_data_);
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      GdkDragContext* context,
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      gint x, gint y,
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      guint time) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (context_ != context) {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    context_ = context;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drop_data_.reset(new WebDropData);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bookmark_drag_data_.Clear();
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    is_drop_target_ = false;
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // text/plain must come before text/uri-list. This is a hack that works in
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // conjunction with OnDragDataReceived. Since some file managers populate
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // text/plain with file URLs when dragging files, we want to handle
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // text/uri-list after text/plain so that the plain text can be cleared if
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // it's a file drag.
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    static int supported_targets[] = {
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::TEXT_PLAIN,
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::TEXT_URI_LIST,
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::TEXT_HTML,
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::NETSCAPE_URL,
11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::CHROME_NAMED_URL,
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(estade): support image drags?
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // Add the bookmark target as well.
116731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    data_requests_ = arraysize(supported_targets) + 1;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_drag_get_data(widget_, context,
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                        ui::GetAtomForTarget(supported_targets[i]),
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        time);
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
122731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
123731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    gtk_drag_get_data(widget_, context, GetBookmarkTargetAtom(), time);
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (data_requests_ == 0) {
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_contents_->render_view_host()->
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DragTargetDragOver(
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            gtk_util::ClientPoint(widget_),
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            gtk_util::ScreenPoint(widget_),
129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            gtk_util::GdkDragActionToWebDragOp(context->actions));
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_contents_->GetBookmarkDragDelegate())
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_contents_->GetBookmarkDragDelegate()->OnDragOver(bookmark_drag_data_);
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drag_over_time_ = time;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Pretend we are a drag destination because we don't want to wait for
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the renderer to tell us if we really are or not.
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebDragDestGtk::OnDragDataReceived(
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GtkSelectionData* data, guint info, guint time) {
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We might get the data from an old get_data() request that we no longer
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // care about.
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (context != context_)
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_requests_--;
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Decode the data.
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data->data && data->length > 0) {
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the source can't provide us with valid data for a requested target,
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // data->data will be NULL.
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (data->target == ui::GetAtomForTarget(ui::TEXT_PLAIN)) {
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      guchar* text = gtk_selection_data_get_text(data);
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (text) {
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        drop_data_->plain_text =
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    data->length));
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        g_free(text);
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (data->target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) {
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gchar** uris = gtk_selection_data_get_uris(data);
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (uris) {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        drop_data_->url = GURL();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // Most file managers populate text/uri-list with file URLs when
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // dragging files. To avoid exposing file system paths to web content,
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // file URLs are never set as the URL content for the drop.
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // TODO(estade): Can the filenames have a non-UTF8 encoding?
171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          GURL url(*uri_iter);
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          FilePath file_path;
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          if (url.SchemeIs(chrome::kFileScheme) &&
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch              net::FileURLToFilePath(url, &file_path)) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // This is a hack. Some file managers also populate text/plain with
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // a file URL when dragging files, so we clear it to avoid exposing
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // it to the web content.
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            drop_data_->plain_text.clear();
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          } else if (!drop_data_->url.is_valid()) {
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            // Also set the first non-file URL as the URL content for the drop.
182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            drop_data_->url = url;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          }
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        g_strfreev(uris);
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (data->target == ui::GetAtomForTarget(ui::TEXT_HTML)) {
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(estade): Can the html have a non-UTF8 encoding?
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      drop_data_->text_html =
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  data->length));
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // We leave the base URL empty.
19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (data->target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) {
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string netscape_url(reinterpret_cast<char*>(data->data),
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               data->length);
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      size_t split = netscape_url.find_first_of('\n');
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (split != std::string::npos) {
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        drop_data_->url = GURL(netscape_url.substr(0, split));
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (split < netscape_url.size() - 1)
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (data->target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) {
20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title);
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // doesn't have any data available for us. In this case we try to synthesize a
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URL bookmark.
210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // Note that bookmark drag data is encoded in the same format for both
211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // GTK and Views, hence we can share the same logic here.
212731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (data->target == GetBookmarkTargetAtom()) {
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (data->data && data->length > 0) {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_drag_data_.ReadFromVector(
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          bookmark_utils::GetNodesFromSelection(
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              NULL, data,
21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              ui::CHROME_BOOKMARK_ITEM,
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              tab_contents_->profile(), NULL, NULL));
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_drag_data_.SetOriginatingProfile(tab_contents_->profile());
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                        drop_data_->url_title);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data_requests_ == 0) {
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Tell the renderer about the drag.
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // |x| and |y| are seemingly arbitrary at this point.
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_contents_->render_view_host()->
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DragTargetDragEnter(*drop_data_.get(),
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            gtk_util::ClientPoint(widget_),
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            gtk_util::ScreenPoint(widget_),
233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick            gtk_util::GdkDragActionToWebDragOp(context->actions));
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // This is non-null if tab_contents_ is showing an ExtensionWebUI with
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // support for (at the moment experimental) drag and drop extensions.
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab_contents_->GetBookmarkDragDelegate()) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_contents_->GetBookmarkDragDelegate()->OnDragEnter(
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          bookmark_drag_data_);
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    drag_over_time_ = time;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The drag has left our widget; forward this information to the renderer.
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 guint time) {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set |context_| to NULL to make sure we will recognize the next DragMotion
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // as an enter.
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  context_ = NULL;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  drop_data_.reset();
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // preceded by a drag-leave. The renderer doesn't like getting the signals
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // in this order so delay telling it about the drag-leave till we are sure
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we are not getting a drop as well.
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoop::current()->PostTask(FROM_HERE,
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Called by GTK when the user releases the mouse, executing a drop.
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    gint x, gint y, guint time) {
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Cancel that drag leave!
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  method_factory_.RevokeAll();
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_contents_->render_view_host()->
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DragTargetDrop(gtk_util::ClientPoint(widget_),
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     gtk_util::ScreenPoint(widget_));
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // This is non-null if tab_contents_ is showing an ExtensionWebUI with
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // support for (at the moment experimental) drag and drop extensions.
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (tab_contents_->GetBookmarkDragDelegate())
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab_contents_->GetBookmarkDragDelegate()->OnDrop(bookmark_drag_data_);
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The second parameter is just an educated guess as to whether or not the
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // drag succeeded, but at least we will get the drag-end animation right
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // sometimes.
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_drag_finish(context, is_drop_target_, FALSE, time);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
282