172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/tab_contents_drag_source.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/mime_util.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/download/download_util.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/drag_download_file.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/drag_download_util.h" 1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h" 16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h" 17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host_delegate.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents_view.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/file_stream.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_util.h" 2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/dragdrop/gtk_dnd_util.h" 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/gtk_util.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/webdropdata.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebDragOperation; 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebDragOperationsMask; 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebDragOperationNone; 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabContentsDragSource::TabContentsDragSource( 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContentsView* tab_contents_view) 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : tab_contents_view_(tab_contents_view), 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_pixbuf_(NULL), 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_failed_(false), 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_widget_(gtk_invisible_new()), 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen drag_context_(NULL), 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_icon_(gtk_window_new(GTK_WINDOW_POPUP)) { 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch signals_.Connect(drag_widget_, "drag-failed", 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragFailedThunk), this); 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch signals_.Connect(drag_widget_, "drag-begin", 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragBeginThunk), 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this); 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch signals_.Connect(drag_widget_, "drag-end", 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragEndThunk), this); 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch signals_.Connect(drag_widget_, "drag-data-get", 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragDataGetThunk), this); 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch signals_.Connect(drag_icon_, "expose-event", 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDragIconExposeThunk), this); 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabContentsDragSource::~TabContentsDragSource() { 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Break the current drag, if any. 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drop_data_.get()) { 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_grab_add(drag_widget_); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_grab_remove(drag_widget_); 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->RemoveObserver(this); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_data_.reset(); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch gtk_widget_destroy(drag_widget_); 62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch gtk_widget_destroy(drag_icon_); 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabContents* TabContentsDragSource::tab_contents() const { 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tab_contents_view_->tab_contents(); 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsDragSource::StartDragging(const WebDropData& drop_data, 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebDragOperationsMask allowed_ops, 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkEventButton* last_mouse_down, 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkBitmap& image, 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Point& image_offset) { 7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Guard against re-starting before previous drag completed. 7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (drag_context_) { 7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED(); 7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen tab_contents()->SystemDragEnded(); 7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int targets_mask = 0; 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_data.plain_text.empty()) 8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::TEXT_PLAIN; 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drop_data.url.is_valid()) { 8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::TEXT_URI_LIST; 8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::CHROME_NAMED_URL; 8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::NETSCAPE_URL; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_data.text_html.empty()) 9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::TEXT_HTML; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_data.file_contents.empty()) 9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::CHROME_WEBDROP_FILE_CONTENTS; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drop_data.download_metadata.empty() && 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_download_util::ParseDownloadMetadata(drop_data.download_metadata, 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &wide_download_mime_type_, 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &download_file_name_, 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &download_url_)) { 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen targets_mask |= ui::DIRECT_SAVE_FILE; 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // NOTE: Begin a drag even if no targets present. Otherwise, things like 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // draggable list elements will not work. 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_data_.reset(new WebDropData(drop_data)); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The image we get from WebKit makes heavy use of alpha-shading. This looks 1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // bad on non-compositing WMs. Fall back to the default drag icon. 1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!image.isNull() && gtk_util::IsScreenComposited()) 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_pixbuf_ = gfx::GdkPixbufFromSkBitmap(&image); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch image_offset_ = image_offset; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GtkTargetList* list = ui::GetTargetListFromCodeMask(targets_mask); 11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (targets_mask & ui::CHROME_WEBDROP_FILE_CONTENTS) { 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_file_mime_type_ = gdk_atom_intern( 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mime_util::GetDataMimeType(drop_data.file_contents).c_str(), FALSE); 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_target_list_add(list, drag_file_mime_type_, 11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 0, ui::CHROME_WEBDROP_FILE_CONTENTS); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_failed_ = false; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we don't pass an event, GDK won't know what event time to start grabbing 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // mouse events. Technically it's the mouse motion event and not the mouse 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // down event that causes the drag, but there's no reliable way to know 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // *which* motion event initiated the drag, so this will have to do. 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(estade): This can sometimes be very far off, e.g. if the user clicks 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and holds and doesn't start dragging for a long time. I doubt it matters 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // much, but we should probably look into the possibility of getting the 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // initiating event from webkit. 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen drag_context_ = gtk_drag_begin(drag_widget_, list, 131731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick gtk_util::WebDragOpToGdkDragAction(allowed_ops), 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1, // Drags are always initiated by the left button. 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<GdkEvent*>(last_mouse_down)); 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The drag adds a ref; let it own the list. 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_target_list_unref(list); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sometimes the drag fails to start; |context| will be NULL and we won't 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // get a drag-end signal. 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!drag_context_) { 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen drag_failed_ = true; 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_data_.reset(); 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen tab_contents()->SystemDragEnded(); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->AddObserver(this); 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsDragSource::WillProcessEvent(GdkEvent* event) { 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No-op. 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsDragSource::DidProcessEvent(GdkEvent* event) { 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (event->type != GDK_MOTION_NOTIFY) 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkEventMotion* event_motion = reinterpret_cast<GdkEventMotion*>(event); 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point client = gtk_util::ClientPoint(GetContentNativeView()); 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_contents()->render_view_host()) { 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents()->render_view_host()->DragSourceMovedTo( 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client.x(), client.y(), 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(event_motion->x_root), 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(event_motion->y_root)); 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsDragSource::OnDragDataGet(GtkWidget* sender, 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkDragContext* context, GtkSelectionData* selection_data, 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch guint target_type, guint time) { 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int kBitsPerByte = 8; 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (target_type) { 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::TEXT_PLAIN: { 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string utf8_text = UTF16ToUTF8(drop_data_->plain_text); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_selection_data_set_text(selection_data, utf8_text.c_str(), 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch utf8_text.length()); 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::TEXT_HTML: { 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(estade): change relative links to be absolute using 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |html_base_url|. 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string utf8_text = UTF16ToUTF8(drop_data_->text_html); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_selection_data_set(selection_data, 18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::GetAtomForTarget(ui::TEXT_HTML), 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kBitsPerByte, 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<const guchar*>(utf8_text.c_str()), 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch utf8_text.length()); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::TEXT_URI_LIST: 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::CHROME_NAMED_URL: 19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::NETSCAPE_URL: { 19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::WriteURLWithName(selection_data, drop_data_->url, 19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen drop_data_->url_title, target_type); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::CHROME_WEBDROP_FILE_CONTENTS: { 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_selection_data_set( 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selection_data, 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_file_mime_type_, kBitsPerByte, 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<const guchar*>(drop_data_->file_contents.data()), 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_data_->file_contents.length()); 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case ui::DIRECT_SAVE_FILE: { 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch char status_code = 'E'; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Retrieves the full file path (in file URL format) provided by the 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // drop target by reading from the source window's XdndDirectSave0 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // property. 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gint file_url_len = 0; 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch guchar* file_url_value = NULL; 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (gdk_property_get(context->source_window, 21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE), 22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::GetAtomForTarget(ui::TEXT_PLAIN_NO_CHARSET), 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1024, 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FALSE, 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &file_url_len, 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &file_url_value) && 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_url_value) { 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Convert from the file url to the file path. 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GURL file_url(std::string(reinterpret_cast<char*>(file_url_value), 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch file_url_len)); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_free(file_url_value); 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath file_path; 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (net::FileURLToFilePath(file_url, &file_path)) { 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Open the file as a stream. 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch net::FileStream* file_stream = 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_download_util::CreateFileStreamForDrop(&file_path); 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (file_stream) { 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start downloading the file to the stream. 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TabContents* tab_contents = tab_contents_view_->tab_contents(); 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<DragDownloadFile> drag_file_downloader = 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new DragDownloadFile(file_path, 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch linked_ptr<net::FileStream>(file_stream), 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch download_url_, 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents->GetURL(), 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents->encoding(), 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents); 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_file_downloader->Start( 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new drag_download_util::PromiseFileFinalizer( 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_file_downloader)); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the status code to success. 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch status_code = 'S'; 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Return the status code to the file manager. 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_selection_data_set(selection_data, 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selection_data->target, 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 8, 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<guchar*>(&status_code), 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1); 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabContentsDragSource::OnDragFailed(GtkWidget* sender, 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkDragContext* context, 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkDragResult result) { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_failed_ = true; 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point root = gtk_util::ScreenPoint(GetContentNativeView()); 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point client = gtk_util::ClientPoint(GetContentNativeView()); 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_contents()->render_view_host()) { 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents()->render_view_host()->DragSourceEndedAt( 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client.x(), client.y(), root.x(), root.y(), 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebDragOperationNone); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Let the native failure animation run. 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FALSE; 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsDragSource::OnDragBegin(GtkWidget* sender, 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkDragContext* drag_context) { 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!download_url_.is_empty()) { 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Generate the file name based on both mime type and proposed file name. 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string download_mime_type = UTF16ToUTF8(wide_download_mime_type_); 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string content_disposition("attachment; filename="); 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_disposition += download_file_name_.value(); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath generated_download_file_name; 2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_util::GenerateFileName(download_url_, 2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick content_disposition, 3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::string(), 3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick download_mime_type, 3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick &generated_download_file_name); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Pass the file name to the drop target by setting the source window's 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // XdndDirectSave0 property. 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_property_change(drag_context->source_window, 30772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE), 30872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::GetAtomForTarget(ui::TEXT_PLAIN_NO_CHARSET), 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 8, 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GDK_PROP_MODE_REPLACE, 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<const guchar*>( 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch generated_download_file_name.value().c_str()), 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch generated_download_file_name.value().length()); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drag_pixbuf_) { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_size_request(drag_icon_, 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_pixbuf_get_width(drag_pixbuf_), 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_pixbuf_get_height(drag_pixbuf_)); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We only need to do this once. 3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!GTK_WIDGET_REALIZED(drag_icon_)) { 3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GdkScreen* screen = gtk_widget_get_screen(drag_icon_); 3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen); 3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (rgba) 3263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gtk_widget_set_colormap(drag_icon_, rgba); 3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_drag_set_icon_widget(drag_context, drag_icon_, 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch image_offset_.x(), image_offset_.y()); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabContentsDragSource::OnDragEnd(GtkWidget* sender, 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkDragContext* drag_context) { 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (drag_pixbuf_) { 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_object_unref(drag_pixbuf_); 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drag_pixbuf_ = NULL; 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoopForUI::current()->RemoveObserver(this); 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!download_url_.is_empty()) { 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_property_delete(drag_context->source_window, 34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE)); 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!drag_failed_) { 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point root = gtk_util::ScreenPoint(GetContentNativeView()); 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point client = gtk_util::ClientPoint(GetContentNativeView()); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tab_contents()->render_view_host()) { 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tab_contents()->render_view_host()->DragSourceEndedAt( 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client.x(), client.y(), root.x(), root.y(), 355731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick gtk_util::GdkDragActionToWebDragOp(drag_context->action)); 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen tab_contents()->SystemDragEnded(); 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch drop_data_.reset(); 36272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen drag_context_ = NULL; 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::NativeView TabContentsDragSource::GetContentNativeView() const { 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tab_contents_view_->GetContentNativeView(); 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabContentsDragSource::OnDragIconExpose(GtkWidget* sender, 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkEventExpose* event) { 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_t* cr = gdk_cairo_create(event->window); 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_cairo_rectangle(cr, &event->area); 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_clip(cr); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_cairo_set_source_pixbuf(cr, drag_pixbuf_, 0, 0); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_paint(cr); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_destroy(cr); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return TRUE; 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 381