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