| 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 |