Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(452)

Side by Side Diff: content/browser/tab_contents/web_drag_dest_gtk.cc

Issue 10014024: TabContents -> WebContentsImpl, part 2. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "content/browser/tab_contents/web_drag_dest_gtk.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/file_path.h"
11 #include "base/message_loop.h"
12 #include "base/utf_string_conversions.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/tab_contents/drag_utils_gtk.h"
15 #include "content/browser/tab_contents/tab_contents.h"
16 #include "content/public/browser/web_drag_dest_delegate.h"
17 #include "content/public/common/url_constants.h"
18 #include "net/base/net_util.h"
19 #include "ui/base/clipboard/custom_data_helper.h"
20 #include "ui/base/dragdrop/gtk_dnd_util.h"
21 #include "ui/base/gtk/gtk_screen_util.h"
22
23 using content::RenderViewHostImpl;
24 using WebKit::WebDragOperation;
25 using WebKit::WebDragOperationNone;
26
27 namespace content {
28
29 WebDragDestGtk::WebDragDestGtk(WebContents* web_contents, GtkWidget* widget)
30 : web_contents_(web_contents),
31 widget_(widget),
32 context_(NULL),
33 data_requests_(0),
34 delegate_(NULL),
35 method_factory_(this) {
36 gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
37 NULL, 0,
38 static_cast<GdkDragAction>(GDK_ACTION_COPY |
39 GDK_ACTION_LINK |
40 GDK_ACTION_MOVE));
41 g_signal_connect(widget, "drag-motion",
42 G_CALLBACK(OnDragMotionThunk), this);
43 g_signal_connect(widget, "drag-leave",
44 G_CALLBACK(OnDragLeaveThunk), this);
45 g_signal_connect(widget, "drag-drop",
46 G_CALLBACK(OnDragDropThunk), this);
47 g_signal_connect(widget, "drag-data-received",
48 G_CALLBACK(OnDragDataReceivedThunk), this);
49 // TODO(tony): Need a drag-data-delete handler for moving content out of
50 // the tab contents. http://crbug.com/38989
51
52 destroy_handler_ = g_signal_connect(
53 widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
54 }
55
56 WebDragDestGtk::~WebDragDestGtk() {
57 if (widget_) {
58 gtk_drag_dest_unset(widget_);
59 g_signal_handler_disconnect(widget_, destroy_handler_);
60 }
61 }
62
63 void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
64 if (context_) {
65 is_drop_target_ = operation != WebDragOperationNone;
66 gdk_drag_status(context_, content::WebDragOpToGdkDragAction(operation),
67 drag_over_time_);
68 }
69 }
70
71 void WebDragDestGtk::DragLeave() {
72 GetRenderViewHost()->DragTargetDragLeave();
73
74 if (delegate())
75 delegate()->OnDragLeave();
76 }
77
78 gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
79 GdkDragContext* context,
80 gint x, gint y,
81 guint time) {
82 if (context_ != context) {
83 context_ = context;
84 drop_data_.reset(new WebDropData);
85 is_drop_target_ = false;
86
87 if (delegate())
88 delegate()->DragInitialize(web_contents_);
89
90 // text/plain must come before text/uri-list. This is a hack that works in
91 // conjunction with OnDragDataReceived. Since some file managers populate
92 // text/plain with file URLs when dragging files, we want to handle
93 // text/uri-list after text/plain so that the plain text can be cleared if
94 // it's a file drag.
95 static int supported_targets[] = {
96 ui::TEXT_PLAIN,
97 ui::TEXT_URI_LIST,
98 ui::TEXT_HTML,
99 ui::NETSCAPE_URL,
100 ui::CHROME_NAMED_URL,
101 // TODO(estade): support image drags?
102 ui::CUSTOM_DATA,
103 };
104
105 // Add the delegate's requested target if applicable. Need to do this here
106 // since gtk_drag_get_data will dispatch to our drag-data-received.
107 data_requests_ = arraysize(supported_targets) + (delegate() ? 1 : 0);
108 for (size_t i = 0; i < arraysize(supported_targets); ++i) {
109 gtk_drag_get_data(widget_, context,
110 ui::GetAtomForTarget(supported_targets[i]),
111 time);
112 }
113
114 if (delegate()) {
115 gtk_drag_get_data(widget_, context, delegate()->GetBookmarkTargetAtom(),
116 time);
117 }
118 } else if (data_requests_ == 0) {
119 GetRenderViewHost()->DragTargetDragOver(
120 ui::ClientPoint(widget_),
121 ui::ScreenPoint(widget_),
122 content::GdkDragActionToWebDragOp(context->actions));
123
124 if (delegate())
125 delegate()->OnDragOver();
126
127 drag_over_time_ = time;
128 }
129
130 // Pretend we are a drag destination because we don't want to wait for
131 // the renderer to tell us if we really are or not.
132 return TRUE;
133 }
134
135 void WebDragDestGtk::OnDragDataReceived(
136 GtkWidget* sender, GdkDragContext* context, gint x, gint y,
137 GtkSelectionData* data, guint info, guint time) {
138 // We might get the data from an old get_data() request that we no longer
139 // care about.
140 if (context != context_)
141 return;
142
143 data_requests_--;
144
145 // Decode the data.
146 gint data_length = gtk_selection_data_get_length(data);
147 const guchar* raw_data = gtk_selection_data_get_data(data);
148 GdkAtom target = gtk_selection_data_get_target(data);
149 if (raw_data && data_length > 0) {
150 // If the source can't provide us with valid data for a requested target,
151 // raw_data will be NULL.
152 if (target == ui::GetAtomForTarget(ui::TEXT_PLAIN)) {
153 guchar* text = gtk_selection_data_get_text(data);
154 if (text) {
155 drop_data_->plain_text =
156 UTF8ToUTF16(std::string(reinterpret_cast<const char*>(text)));
157 g_free(text);
158 }
159 } else if (target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) {
160 gchar** uris = gtk_selection_data_get_uris(data);
161 if (uris) {
162 drop_data_->url = GURL();
163 for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
164 // Most file managers populate text/uri-list with file URLs when
165 // dragging files. To avoid exposing file system paths to web content,
166 // file URLs are never set as the URL content for the drop.
167 // TODO(estade): Can the filenames have a non-UTF8 encoding?
168 GURL url(*uri_iter);
169 FilePath file_path;
170 if (url.SchemeIs(chrome::kFileScheme) &&
171 net::FileURLToFilePath(url, &file_path)) {
172 drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
173 // This is a hack. Some file managers also populate text/plain with
174 // a file URL when dragging files, so we clear it to avoid exposing
175 // it to the web content.
176 drop_data_->plain_text.clear();
177 } else if (!drop_data_->url.is_valid()) {
178 // Also set the first non-file URL as the URL content for the drop.
179 drop_data_->url = url;
180 }
181 }
182 g_strfreev(uris);
183 }
184 } else if (target == ui::GetAtomForTarget(ui::TEXT_HTML)) {
185 // TODO(estade): Can the html have a non-UTF8 encoding?
186 drop_data_->text_html =
187 UTF8ToUTF16(std::string(reinterpret_cast<const char*>(raw_data),
188 data_length));
189 // We leave the base URL empty.
190 } else if (target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) {
191 std::string netscape_url(reinterpret_cast<const char*>(raw_data),
192 data_length);
193 size_t split = netscape_url.find_first_of('\n');
194 if (split != std::string::npos) {
195 drop_data_->url = GURL(netscape_url.substr(0, split));
196 if (split < netscape_url.size() - 1)
197 drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
198 }
199 } else if (target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) {
200 ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title);
201 } else if (target == ui::GetAtomForTarget(ui::CUSTOM_DATA)) {
202 ui::ReadCustomDataIntoMap(
203 raw_data, data_length, &drop_data_->custom_data);
204 }
205 }
206
207 // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
208 // doesn't have any data available for us. In this case we try to synthesize a
209 // URL bookmark.
210 // Note that bookmark drag data is encoded in the same format for both
211 // GTK and Views, hence we can share the same logic here.
212 if (delegate() && target == delegate()->GetBookmarkTargetAtom()) {
213 if (raw_data && data_length > 0) {
214 delegate()->OnReceiveDataFromGtk(data);
215 } else {
216 delegate()->OnReceiveProcessedData(drop_data_->url,
217 drop_data_->url_title);
218 }
219 }
220
221 if (data_requests_ == 0) {
222 // Tell the renderer about the drag.
223 // |x| and |y| are seemingly arbitrary at this point.
224 GetRenderViewHost()->DragTargetDragEnter(
225 *drop_data_.get(),
226 ui::ClientPoint(widget_),
227 ui::ScreenPoint(widget_),
228 content::GdkDragActionToWebDragOp(context->actions));
229
230 if (delegate())
231 delegate()->OnDragEnter();
232
233 drag_over_time_ = time;
234 }
235 }
236
237 // The drag has left our widget; forward this information to the renderer.
238 void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
239 guint time) {
240 // Set |context_| to NULL to make sure we will recognize the next DragMotion
241 // as an enter.
242 context_ = NULL;
243 drop_data_.reset();
244 // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
245 // preceded by a drag-leave. The renderer doesn't like getting the signals
246 // in this order so delay telling it about the drag-leave till we are sure
247 // we are not getting a drop as well.
248 MessageLoop::current()->PostTask(FROM_HERE,
249 base::Bind(&WebDragDestGtk::DragLeave, method_factory_.GetWeakPtr()));
250 }
251
252 // Called by GTK when the user releases the mouse, executing a drop.
253 gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
254 gint x, gint y, guint time) {
255 // Cancel that drag leave!
256 method_factory_.InvalidateWeakPtrs();
257
258 GetRenderViewHost()->
259 DragTargetDrop(ui::ClientPoint(widget_), ui::ScreenPoint(widget_));
260
261 if (delegate())
262 delegate()->OnDrop();
263
264 // The second parameter is just an educated guess as to whether or not the
265 // drag succeeded, but at least we will get the drag-end animation right
266 // sometimes.
267 gtk_drag_finish(context, is_drop_target_, FALSE, time);
268
269 return TRUE;
270 }
271
272 RenderViewHostImpl* WebDragDestGtk::GetRenderViewHost() const {
273 return static_cast<RenderViewHostImpl*>(web_contents_->GetRenderViewHost());
274 }
275
276 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/tab_contents/web_drag_dest_gtk.h ('k') | content/browser/tab_contents/web_drag_dest_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698