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