summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/tab_contents_drag_source.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/gtk/tab_contents_drag_source.cc')
-rw-r--r--chrome/browser/gtk/tab_contents_drag_source.cc112
1 files changed, 111 insertions, 1 deletions
diff --git a/chrome/browser/gtk/tab_contents_drag_source.cc b/chrome/browser/gtk/tab_contents_drag_source.cc
index 15b111c..22b78b2 100644
--- a/chrome/browser/gtk/tab_contents_drag_source.cc
+++ b/chrome/browser/gtk/tab_contents_drag_source.cc
@@ -5,13 +5,19 @@
#include "chrome/browser/gtk/tab_contents_drag_source.h"
#include "app/gtk_dnd_util.h"
+#include "base/file_util.h"
#include "base/mime_util.h"
#include "base/string_util.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/drag_download_file.h"
+#include "chrome/browser/download/drag_download_util.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/gtk_util.h"
+#include "net/base/file_stream.h"
+#include "net/base/net_util.h"
#include "webkit/glue/webdropdata.h"
using WebKit::WebDragOperation;
@@ -25,6 +31,8 @@ TabContentsDragSource::TabContentsDragSource(
drag_widget_ = gtk_invisible_new();
g_signal_connect(drag_widget_, "drag-failed",
G_CALLBACK(OnDragFailedThunk), this);
+ g_signal_connect(drag_widget_, "drag-begin", G_CALLBACK(OnDragBeginThunk),
+ this);
g_signal_connect(drag_widget_, "drag-end", G_CALLBACK(OnDragEndThunk), this);
g_signal_connect(drag_widget_, "drag-data-get",
G_CALLBACK(OnDragDataGetThunk), this);
@@ -35,6 +43,8 @@ TabContentsDragSource::~TabContentsDragSource() {
g_signal_handlers_disconnect_by_func(drag_widget_,
reinterpret_cast<gpointer>(OnDragFailedThunk), this);
g_signal_handlers_disconnect_by_func(drag_widget_,
+ reinterpret_cast<gpointer>(OnDragBeginThunk), this);
+ g_signal_handlers_disconnect_by_func(drag_widget_,
reinterpret_cast<gpointer>(OnDragEndThunk), this);
g_signal_handlers_disconnect_by_func(drag_widget_,
reinterpret_cast<gpointer>(OnDragDataGetThunk), this);
@@ -71,6 +81,13 @@ void TabContentsDragSource::StartDragging(const WebDropData& drop_data,
targets_mask |= GtkDndUtil::TEXT_HTML;
if (!drop_data.file_contents.empty())
targets_mask |= GtkDndUtil::CHROME_WEBDROP_FILE_CONTENTS;
+ if (!drop_data.download_metadata.empty() &&
+ drag_download_util::ParseDownloadMetadata(drop_data.download_metadata,
+ &wide_download_mime_type_,
+ &download_file_name_,
+ &download_url_)) {
+ targets_mask |= GtkDndUtil::DIRECT_SAVE_FILE;
+ }
if (targets_mask == 0) {
NOTIMPLEMENTED();
@@ -179,6 +196,64 @@ void TabContentsDragSource::OnDragDataGet(
break;
}
+ case GtkDndUtil::DIRECT_SAVE_FILE: {
+ char status_code = 'E';
+
+ // Retrieves the full file path (in file URL format) provided by the
+ // drop target by reading from the source window's XdndDirectSave0
+ // property.
+ gint file_url_len = 0;
+ guchar* file_url_value = NULL;
+ if (gdk_property_get(context->source_window,
+ GtkDndUtil::GetAtomForTarget(
+ GtkDndUtil::DIRECT_SAVE_FILE),
+ GtkDndUtil::GetAtomForTarget(
+ GtkDndUtil::TEXT_PLAIN_NO_CHARSET),
+ 0,
+ 1024,
+ FALSE,
+ NULL,
+ NULL,
+ &file_url_len,
+ &file_url_value) &&
+ file_url_value) {
+ // Convert from the file url to the file path.
+ GURL file_url(std::string(reinterpret_cast<char*>(file_url_value),
+ file_url_len));
+ FilePath file_path;
+ if (net::FileURLToFilePath(file_url, &file_path)) {
+ // Open the file as a stream.
+ net::FileStream* file_stream =
+ drag_download_util::CreateFileStreamForDrop(&file_path);
+ if (file_stream) {
+ // Start downloading the file to the stream.
+ TabContents* tab_contents = tab_contents_view_->tab_contents();
+ scoped_refptr<DragDownloadFile> drag_file_downloader =
+ new DragDownloadFile(file_path,
+ linked_ptr<net::FileStream>(file_stream),
+ download_url_,
+ tab_contents->GetURL(),
+ tab_contents->encoding(),
+ tab_contents);
+ drag_file_downloader->Start(
+ new drag_download_util::PromiseFileFinalizer(
+ drag_file_downloader));
+
+ // Set the status code to success.
+ status_code = 'S';
+ }
+ }
+
+ // Return the status code to the file manager.
+ gtk_selection_data_set(selection_data,
+ selection_data->target,
+ 8,
+ reinterpret_cast<guchar*>(&status_code),
+ 1);
+ }
+ break;
+ }
+
default:
NOTREACHED();
}
@@ -200,9 +275,44 @@ gboolean TabContentsDragSource::OnDragFailed() {
return FALSE;
}
-void TabContentsDragSource::OnDragEnd(WebDragOperation operation) {
+void TabContentsDragSource::OnDragBegin(GdkDragContext* drag_context) {
+ if (!download_url_.is_empty()) {
+ // Generate the file name based on both mime type and proposed file name.
+ std::string download_mime_type = UTF16ToUTF8(wide_download_mime_type_);
+ std::string content_disposition("attachment; filename=");
+ content_disposition += download_file_name_.value();
+ FilePath generated_download_file_name;
+ DownloadManager::GenerateFileName(download_url_,
+ content_disposition,
+ std::string(),
+ download_mime_type,
+ &generated_download_file_name);
+
+ // Pass the file name to the drop target by setting the source window's
+ // XdndDirectSave0 property.
+ gdk_property_change(drag_context->source_window,
+ GtkDndUtil::GetAtomForTarget(
+ GtkDndUtil::DIRECT_SAVE_FILE),
+ GtkDndUtil::GetAtomForTarget(
+ GtkDndUtil::TEXT_PLAIN_NO_CHARSET),
+ 8,
+ GDK_PROP_MODE_REPLACE,
+ reinterpret_cast<const guchar*>(
+ generated_download_file_name.value().c_str()),
+ generated_download_file_name.value().length());
+ }
+}
+
+void TabContentsDragSource::OnDragEnd(GdkDragContext* drag_context,
+ WebDragOperation operation) {
MessageLoopForUI::current()->RemoveObserver(this);
+ if (!download_url_.is_empty()) {
+ gdk_property_delete(drag_context->source_window,
+ GtkDndUtil::GetAtomForTarget(
+ GtkDndUtil::DIRECT_SAVE_FILE));
+ }
+
if (!drag_failed_) {
gfx::Point root = gtk_util::ScreenPoint(GetContentNativeView());
gfx::Point client = gtk_util::ClientPoint(GetContentNativeView());