OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/tab_contents/web_drag_dest_gtk.h" | 5 #include "chrome/browser/tab_contents/web_drag_dest_gtk.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/utf_string_conversions.h" | 11 #include "base/utf_string_conversions.h" |
12 #include "chrome/browser/bookmarks/bookmark_node_data.h" | 12 #include "chrome/browser/tab_contents/web_drag_dest_delegate_gtk.h" |
13 #include "chrome/browser/profiles/profile.h" | |
14 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" | |
15 #include "chrome/browser/ui/browser.h" | |
16 #include "chrome/browser/ui/browser_window.h" | |
17 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h" | |
18 #include "chrome/browser/ui/gtk/gtk_util.h" | |
19 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
20 #include "chrome/common/url_constants.h" | |
21 #include "content/browser/renderer_host/render_view_host.h" | 13 #include "content/browser/renderer_host/render_view_host.h" |
| 14 #include "content/browser/tab_contents/drag_utils_gtk.h" |
22 #include "content/browser/tab_contents/tab_contents.h" | 15 #include "content/browser/tab_contents/tab_contents.h" |
| 16 #include "content/common/url_constants.h" |
23 #include "net/base/net_util.h" | 17 #include "net/base/net_util.h" |
24 #include "ui/base/dragdrop/gtk_dnd_util.h" | 18 #include "ui/base/dragdrop/gtk_dnd_util.h" |
| 19 #include "ui/base/gtk/gtk_screen_utils.h" |
25 | 20 |
26 using WebKit::WebDragOperation; | 21 using WebKit::WebDragOperation; |
27 using WebKit::WebDragOperationNone; | 22 using WebKit::WebDragOperationNone; |
28 | 23 |
29 namespace { | |
30 | |
31 // Returns the bookmark target atom, based on the underlying toolkit. | |
32 // | |
33 // For GTK, bookmark drag data is encoded as pickle and associated with | |
34 // ui::CHROME_BOOKMARK_ITEM. See // bookmark_utils::WriteBookmarksToSelection() | |
35 // for details. | |
36 // For Views, bookmark drag data is encoded in the same format, and | |
37 // associated with a custom format. See BookmarkNodeData::Write() for | |
38 // details. | |
39 GdkAtom GetBookmarkTargetAtom() { | |
40 #if defined(TOOLKIT_VIEWS) | |
41 return BookmarkNodeData::GetBookmarkCustomFormat(); | |
42 #else | |
43 return ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM); | |
44 #endif | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget) | 24 WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget) |
50 : tab_contents_(tab_contents), | 25 : tab_contents_(tab_contents), |
51 tab_(NULL), | |
52 widget_(widget), | 26 widget_(widget), |
53 context_(NULL), | 27 context_(NULL), |
| 28 data_requests_(0), |
| 29 delegate_(NULL), |
54 method_factory_(this) { | 30 method_factory_(this) { |
55 gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0), | 31 gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0), |
56 NULL, 0, | 32 NULL, 0, |
57 static_cast<GdkDragAction>(GDK_ACTION_COPY | | 33 static_cast<GdkDragAction>(GDK_ACTION_COPY | |
58 GDK_ACTION_LINK | | 34 GDK_ACTION_LINK | |
59 GDK_ACTION_MOVE)); | 35 GDK_ACTION_MOVE)); |
60 g_signal_connect(widget, "drag-motion", | 36 g_signal_connect(widget, "drag-motion", |
61 G_CALLBACK(OnDragMotionThunk), this); | 37 G_CALLBACK(OnDragMotionThunk), this); |
62 g_signal_connect(widget, "drag-leave", | 38 g_signal_connect(widget, "drag-leave", |
63 G_CALLBACK(OnDragLeaveThunk), this); | 39 G_CALLBACK(OnDragLeaveThunk), this); |
(...skipping 11 matching lines...) Expand all Loading... |
75 WebDragDestGtk::~WebDragDestGtk() { | 51 WebDragDestGtk::~WebDragDestGtk() { |
76 if (widget_) { | 52 if (widget_) { |
77 gtk_drag_dest_unset(widget_); | 53 gtk_drag_dest_unset(widget_); |
78 g_signal_handler_disconnect(widget_, destroy_handler_); | 54 g_signal_handler_disconnect(widget_, destroy_handler_); |
79 } | 55 } |
80 } | 56 } |
81 | 57 |
82 void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) { | 58 void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) { |
83 if (context_) { | 59 if (context_) { |
84 is_drop_target_ = operation != WebDragOperationNone; | 60 is_drop_target_ = operation != WebDragOperationNone; |
85 gdk_drag_status(context_, gtk_util::WebDragOpToGdkDragAction(operation), | 61 gdk_drag_status(context_, content::WebDragOpToGdkDragAction(operation), |
86 drag_over_time_); | 62 drag_over_time_); |
87 } | 63 } |
88 } | 64 } |
89 | 65 |
90 void WebDragDestGtk::DragLeave() { | 66 void WebDragDestGtk::DragLeave() { |
91 tab_contents_->render_view_host()->DragTargetDragLeave(); | 67 tab_contents_->render_view_host()->DragTargetDragLeave(); |
92 | 68 |
93 if (tab_ && tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) | 69 if (delegate()) |
94 tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragLeave( | 70 delegate()->OnDragLeave(); |
95 bookmark_drag_data_); | |
96 } | 71 } |
97 | 72 |
98 gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender, | 73 gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender, |
99 GdkDragContext* context, | 74 GdkDragContext* context, |
100 gint x, gint y, | 75 gint x, gint y, |
101 guint time) { | 76 guint time) { |
102 // Ideally we would want to initialize the the TabContentsWrapper member in | |
103 // the constructor. We cannot do that as the WebDragDestGtk object is | |
104 // created during the construction of the TabContents object. | |
105 // The TabContentsWrapper is created much later. | |
106 if (!tab_) | |
107 tab_ = TabContentsWrapper::GetCurrentWrapperForContents(tab_contents_); | |
108 | |
109 if (context_ != context) { | 77 if (context_ != context) { |
110 context_ = context; | 78 context_ = context; |
111 drop_data_.reset(new WebDropData); | 79 drop_data_.reset(new WebDropData); |
112 bookmark_drag_data_.Clear(); | |
113 is_drop_target_ = false; | 80 is_drop_target_ = false; |
114 | 81 |
| 82 if (delegate()) |
| 83 delegate()->DragInitialize(tab_contents_); |
| 84 |
115 // text/plain must come before text/uri-list. This is a hack that works in | 85 // text/plain must come before text/uri-list. This is a hack that works in |
116 // conjunction with OnDragDataReceived. Since some file managers populate | 86 // conjunction with OnDragDataReceived. Since some file managers populate |
117 // text/plain with file URLs when dragging files, we want to handle | 87 // text/plain with file URLs when dragging files, we want to handle |
118 // text/uri-list after text/plain so that the plain text can be cleared if | 88 // text/uri-list after text/plain so that the plain text can be cleared if |
119 // it's a file drag. | 89 // it's a file drag. |
120 static int supported_targets[] = { | 90 static int supported_targets[] = { |
121 ui::TEXT_PLAIN, | 91 ui::TEXT_PLAIN, |
122 ui::TEXT_URI_LIST, | 92 ui::TEXT_URI_LIST, |
123 ui::TEXT_HTML, | 93 ui::TEXT_HTML, |
124 ui::NETSCAPE_URL, | 94 ui::NETSCAPE_URL, |
125 ui::CHROME_NAMED_URL, | 95 ui::CHROME_NAMED_URL, |
126 // TODO(estade): support image drags? | 96 // TODO(estade): support image drags? |
127 }; | 97 }; |
128 | 98 |
129 // Add the bookmark target as well. | 99 // Add the delegate's requested target if applicable. Need to do this here |
130 data_requests_ = arraysize(supported_targets) + 1; | 100 // since gtk_drag_get_data will dispatch to our drag-data-received. |
| 101 data_requests_ = arraysize(supported_targets) + (delegate() ? 1 : 0); |
131 for (size_t i = 0; i < arraysize(supported_targets); ++i) { | 102 for (size_t i = 0; i < arraysize(supported_targets); ++i) { |
132 gtk_drag_get_data(widget_, context, | 103 gtk_drag_get_data(widget_, context, |
133 ui::GetAtomForTarget(supported_targets[i]), | 104 ui::GetAtomForTarget(supported_targets[i]), |
134 time); | 105 time); |
135 } | 106 } |
136 | 107 |
137 gtk_drag_get_data(widget_, context, GetBookmarkTargetAtom(), time); | 108 if (delegate()) { |
| 109 gtk_drag_get_data(widget_, context, delegate()->GetBookmarkTargetAtom(), |
| 110 time); |
| 111 } |
138 } else if (data_requests_ == 0) { | 112 } else if (data_requests_ == 0) { |
139 tab_contents_->render_view_host()-> | 113 tab_contents_->render_view_host()-> |
140 DragTargetDragOver( | 114 DragTargetDragOver( |
141 gtk_util::ClientPoint(widget_), | 115 ui::ClientPoint(widget_), |
142 gtk_util::ScreenPoint(widget_), | 116 ui::ScreenPoint(widget_), |
143 gtk_util::GdkDragActionToWebDragOp(context->actions)); | 117 content::GdkDragActionToWebDragOp(context->actions)); |
144 if (tab_ && tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) | 118 |
145 tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragOver( | 119 if (delegate()) |
146 bookmark_drag_data_); | 120 delegate()->OnDragOver(); |
| 121 |
147 drag_over_time_ = time; | 122 drag_over_time_ = time; |
148 } | 123 } |
149 | 124 |
150 // Pretend we are a drag destination because we don't want to wait for | 125 // Pretend we are a drag destination because we don't want to wait for |
151 // the renderer to tell us if we really are or not. | 126 // the renderer to tell us if we really are or not. |
152 return TRUE; | 127 return TRUE; |
153 } | 128 } |
154 | 129 |
155 void WebDragDestGtk::OnDragDataReceived( | 130 void WebDragDestGtk::OnDragDataReceived( |
156 GtkWidget* sender, GdkDragContext* context, gint x, gint y, | 131 GtkWidget* sender, GdkDragContext* context, gint x, gint y, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 } else if (data->target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) { | 191 } else if (data->target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) { |
217 ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title); | 192 ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title); |
218 } | 193 } |
219 } | 194 } |
220 | 195 |
221 // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source | 196 // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source |
222 // doesn't have any data available for us. In this case we try to synthesize a | 197 // doesn't have any data available for us. In this case we try to synthesize a |
223 // URL bookmark. | 198 // URL bookmark. |
224 // Note that bookmark drag data is encoded in the same format for both | 199 // Note that bookmark drag data is encoded in the same format for both |
225 // GTK and Views, hence we can share the same logic here. | 200 // GTK and Views, hence we can share the same logic here. |
226 if (data->target == GetBookmarkTargetAtom()) { | 201 if (delegate() && data->target == delegate()->GetBookmarkTargetAtom()) { |
227 if (data->data && data->length > 0) { | 202 if (data->data && data->length > 0) { |
228 Profile* profile = | 203 delegate()->OnReceiveDataFromGtk(data); |
229 Profile::FromBrowserContext(tab_contents_->browser_context()); | |
230 bookmark_drag_data_.ReadFromVector( | |
231 bookmark_utils::GetNodesFromSelection( | |
232 NULL, data, | |
233 ui::CHROME_BOOKMARK_ITEM, | |
234 profile, NULL, NULL)); | |
235 bookmark_drag_data_.SetOriginatingProfile(profile); | |
236 } else { | 204 } else { |
237 bookmark_drag_data_.ReadFromTuple(drop_data_->url, | 205 delegate()->OnReceiveProcessedData(drop_data_->url, |
238 drop_data_->url_title); | 206 drop_data_->url_title); |
239 } | 207 } |
240 } | 208 } |
241 | 209 |
242 if (data_requests_ == 0) { | 210 if (data_requests_ == 0) { |
243 // Tell the renderer about the drag. | 211 // Tell the renderer about the drag. |
244 // |x| and |y| are seemingly arbitrary at this point. | 212 // |x| and |y| are seemingly arbitrary at this point. |
245 tab_contents_->render_view_host()-> | 213 tab_contents_->render_view_host()-> |
246 DragTargetDragEnter(*drop_data_.get(), | 214 DragTargetDragEnter(*drop_data_.get(), |
247 gtk_util::ClientPoint(widget_), | 215 ui::ClientPoint(widget_), |
248 gtk_util::ScreenPoint(widget_), | 216 ui::ScreenPoint(widget_), |
249 gtk_util::GdkDragActionToWebDragOp(context->actions)); | 217 content::GdkDragActionToWebDragOp(context->actions)); |
250 | 218 |
251 // This is non-null if tab_contents_ is showing an ExtensionWebUI with | 219 if (delegate()) |
252 // support for (at the moment experimental) drag and drop extensions. | 220 delegate()->OnDragEnter(); |
253 if (tab_ && tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) | 221 |
254 tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDragEnter( | |
255 bookmark_drag_data_); | |
256 drag_over_time_ = time; | 222 drag_over_time_ = time; |
257 } | 223 } |
258 } | 224 } |
259 | 225 |
260 // The drag has left our widget; forward this information to the renderer. | 226 // The drag has left our widget; forward this information to the renderer. |
261 void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context, | 227 void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context, |
262 guint time) { | 228 guint time) { |
263 // Set |context_| to NULL to make sure we will recognize the next DragMotion | 229 // Set |context_| to NULL to make sure we will recognize the next DragMotion |
264 // as an enter. | 230 // as an enter. |
265 context_ = NULL; | 231 context_ = NULL; |
266 drop_data_.reset(); | 232 drop_data_.reset(); |
267 // When GTK sends us a drag-drop signal, it is shortly (and synchronously) | 233 // When GTK sends us a drag-drop signal, it is shortly (and synchronously) |
268 // preceded by a drag-leave. The renderer doesn't like getting the signals | 234 // preceded by a drag-leave. The renderer doesn't like getting the signals |
269 // in this order so delay telling it about the drag-leave till we are sure | 235 // in this order so delay telling it about the drag-leave till we are sure |
270 // we are not getting a drop as well. | 236 // we are not getting a drop as well. |
271 MessageLoop::current()->PostTask(FROM_HERE, | 237 MessageLoop::current()->PostTask(FROM_HERE, |
272 method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave)); | 238 method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave)); |
273 } | 239 } |
274 | 240 |
275 // Called by GTK when the user releases the mouse, executing a drop. | 241 // Called by GTK when the user releases the mouse, executing a drop. |
276 gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context, | 242 gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context, |
277 gint x, gint y, guint time) { | 243 gint x, gint y, guint time) { |
278 // Cancel that drag leave! | 244 // Cancel that drag leave! |
279 method_factory_.RevokeAll(); | 245 method_factory_.RevokeAll(); |
280 | 246 |
281 tab_contents_->render_view_host()-> | 247 tab_contents_->render_view_host()-> |
282 DragTargetDrop(gtk_util::ClientPoint(widget_), | 248 DragTargetDrop(ui::ClientPoint(widget_), ui::ScreenPoint(widget_)); |
283 gtk_util::ScreenPoint(widget_)); | |
284 | 249 |
285 // This is non-null if tab_contents_ is showing an ExtensionWebUI with | 250 if (delegate()) |
286 // support for (at the moment experimental) drag and drop extensions. | 251 delegate()->OnDrop(); |
287 if (tab_ && tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()) | |
288 tab_->bookmark_tab_helper()->GetBookmarkDragDelegate()->OnDrop( | |
289 bookmark_drag_data_); | |
290 | |
291 // Focus the target browser. | |
292 Browser* browser = Browser::GetBrowserForController( | |
293 &tab_contents_->controller(), NULL); | |
294 if (browser) | |
295 browser->window()->Show(); | |
296 | 252 |
297 // The second parameter is just an educated guess as to whether or not the | 253 // The second parameter is just an educated guess as to whether or not the |
298 // drag succeeded, but at least we will get the drag-end animation right | 254 // drag succeeded, but at least we will get the drag-end animation right |
299 // sometimes. | 255 // sometimes. |
300 gtk_drag_finish(context, is_drop_target_, FALSE, time); | 256 gtk_drag_finish(context, is_drop_target_, FALSE, time); |
301 | 257 |
302 return TRUE; | 258 return TRUE; |
303 } | 259 } |
OLD | NEW |