This source file includes following definitions.
- drag_icon_
- StartDragging
- OnDragDataGet
- OnDragFailed
- OnDragBegin
- OnDragEnd
- GetContentNativeView
- OnDragIconExpose
#include "content/browser/web_contents/web_drag_source_gtk.h"
#include <string>
#include "base/files/file.h"
#include "base/nix/mime_util_xdg.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/download/drag_download_file.h"
#include "content/browser/download/drag_download_util.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/drag_utils_gtk.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/content_client.h"
#include "content/public/common/drop_data.h"
#include "net/base/net_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/dragdrop/gtk_dnd_util.h"
#include "ui/base/gtk/gtk_screen_util.h"
#include "ui/gfx/gtk_compat.h"
#include "ui/gfx/gtk_util.h"
using blink::WebDragOperation;
using blink::WebDragOperationsMask;
using blink::WebDragOperationNone;
namespace content {
WebDragSourceGtk::WebDragSourceGtk(WebContents* web_contents)
: web_contents_(static_cast<WebContentsImpl*>(web_contents)),
drag_pixbuf_(NULL),
drag_failed_(false),
drag_widget_(gtk_invisible_new()),
drag_context_(NULL),
drag_icon_(gtk_window_new(GTK_WINDOW_POPUP)) {
signals_.Connect(drag_widget_, "drag-failed",
G_CALLBACK(OnDragFailedThunk), this);
signals_.Connect(drag_widget_, "drag-begin",
G_CALLBACK(OnDragBeginThunk),
this);
signals_.Connect(drag_widget_, "drag-end",
G_CALLBACK(OnDragEndThunk), this);
signals_.Connect(drag_widget_, "drag-data-get",
G_CALLBACK(OnDragDataGetThunk), this);
signals_.Connect(drag_icon_, "expose-event",
G_CALLBACK(OnDragIconExposeThunk), this);
}
WebDragSourceGtk::~WebDragSourceGtk() {
if (drop_data_) {
gtk_grab_add(drag_widget_);
gtk_grab_remove(drag_widget_);
drop_data_.reset();
}
gtk_widget_destroy(drag_widget_);
gtk_widget_destroy(drag_icon_);
}
bool WebDragSourceGtk::StartDragging(const DropData& drop_data,
WebDragOperationsMask allowed_ops,
GdkEventButton* last_mouse_down,
const SkBitmap& image,
const gfx::Vector2d& image_offset) {
if (drag_context_) {
NOTREACHED();
return false;
}
int targets_mask = ui::RENDERER_TAINT;
if (!drop_data.text.string().empty())
targets_mask |= ui::TEXT_PLAIN;
if (drop_data.url.is_valid()) {
targets_mask |= ui::TEXT_URI_LIST;
targets_mask |= ui::CHROME_NAMED_URL;
targets_mask |= ui::NETSCAPE_URL;
}
if (!drop_data.html.string().empty())
targets_mask |= ui::TEXT_HTML;
if (!drop_data.file_contents.empty())
targets_mask |= ui::CHROME_WEBDROP_FILE_CONTENTS;
if (!drop_data.download_metadata.empty() &&
ParseDownloadMetadata(drop_data.download_metadata,
&wide_download_mime_type_,
&download_file_name_,
&download_url_)) {
targets_mask |= ui::DIRECT_SAVE_FILE;
}
if (!drop_data.custom_data.empty())
targets_mask |= ui::CUSTOM_DATA;
drop_data_.reset(new DropData(drop_data));
if (!image.isNull() && ui::IsScreenComposited())
drag_pixbuf_ = gfx::GdkPixbufFromSkBitmap(image);
image_offset_ = image_offset;
GtkTargetList* list = ui::GetTargetListFromCodeMask(targets_mask);
if (targets_mask & ui::CHROME_WEBDROP_FILE_CONTENTS) {
base::ThreadRestrictions::ScopedAllowIO allow_io;
drag_file_mime_type_ = gdk_atom_intern(
base::nix::GetDataMimeType(drop_data.file_contents).c_str(), FALSE);
gtk_target_list_add(list, drag_file_mime_type_,
0, ui::CHROME_WEBDROP_FILE_CONTENTS);
}
drag_failed_ = false;
drag_context_ = gtk_drag_begin(drag_widget_, list,
WebDragOpToGdkDragAction(allowed_ops),
1,
reinterpret_cast<GdkEvent*>(last_mouse_down));
gtk_target_list_unref(list);
if (!drag_context_) {
drag_failed_ = true;
drop_data_.reset();
return false;
}
return true;
}
void WebDragSourceGtk::OnDragDataGet(GtkWidget* sender,
GdkDragContext* context,
GtkSelectionData* selection_data,
guint target_type,
guint time) {
const int kBitsPerByte = 8;
switch (target_type) {
case ui::TEXT_PLAIN: {
std::string utf8_text = base::UTF16ToUTF8(drop_data_->text.string());
gtk_selection_data_set_text(selection_data, utf8_text.c_str(),
utf8_text.length());
break;
}
case ui::TEXT_HTML: {
std::string utf8_text = base::UTF16ToUTF8(drop_data_->html.string());
gtk_selection_data_set(selection_data,
ui::GetAtomForTarget(ui::TEXT_HTML),
kBitsPerByte,
reinterpret_cast<const guchar*>(utf8_text.c_str()),
utf8_text.length());
break;
}
case ui::TEXT_URI_LIST:
case ui::CHROME_NAMED_URL:
case ui::NETSCAPE_URL: {
ui::WriteURLWithName(selection_data, drop_data_->url,
drop_data_->url_title, target_type);
break;
}
case ui::CHROME_WEBDROP_FILE_CONTENTS: {
gtk_selection_data_set(
selection_data,
drag_file_mime_type_, kBitsPerByte,
reinterpret_cast<const guchar*>(drop_data_->file_contents.data()),
drop_data_->file_contents.length());
break;
}
case ui::DIRECT_SAVE_FILE: {
char status_code = 'E';
gint file_url_len = 0;
guchar* file_url_value = NULL;
if (gdk_property_get(context->source_window,
ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE),
ui::GetAtomForTarget(ui::TEXT_PLAIN_NO_CHARSET),
0,
1024,
FALSE,
NULL,
NULL,
&file_url_len,
&file_url_value) &&
file_url_value) {
GURL file_url(std::string(reinterpret_cast<char*>(file_url_value),
file_url_len));
g_free(file_url_value);
base::FilePath file_path;
if (net::FileURLToFilePath(file_url, &file_path)) {
base::File file(CreateFileForDrop(&file_path));
if (file.IsValid()) {
scoped_refptr<DragDownloadFile> drag_file_downloader =
new DragDownloadFile(
file_path,
file.Pass(),
download_url_,
Referrer(web_contents_->GetURL(),
drop_data_->referrer_policy),
web_contents_->GetEncoding(),
web_contents_);
drag_file_downloader->Start(
new PromiseFileFinalizer(drag_file_downloader.get()));
status_code = 'S';
}
}
gtk_selection_data_set(selection_data,
gtk_selection_data_get_target(selection_data),
kBitsPerByte,
reinterpret_cast<guchar*>(&status_code),
1);
}
break;
}
case ui::CUSTOM_DATA: {
Pickle custom_data;
ui::WriteCustomDataToPickle(drop_data_->custom_data, &custom_data);
gtk_selection_data_set(
selection_data,
ui::GetAtomForTarget(ui::CUSTOM_DATA),
kBitsPerByte,
reinterpret_cast<const guchar*>(custom_data.data()),
custom_data.size());
break;
}
case ui::RENDERER_TAINT: {
static const char kPlaceholder[] = "x";
gtk_selection_data_set(
selection_data,
ui::GetAtomForTarget(ui::RENDERER_TAINT),
kBitsPerByte,
reinterpret_cast<const guchar*>(kPlaceholder),
strlen(kPlaceholder));
break;
}
default:
NOTREACHED();
}
}
gboolean WebDragSourceGtk::OnDragFailed(GtkWidget* sender,
GdkDragContext* context,
GtkDragResult result) {
drag_failed_ = true;
gfx::Point root = ui::ScreenPoint(GetContentNativeView());
gfx::Point client = ui::ClientPoint(GetContentNativeView());
if (web_contents_) {
web_contents_->DragSourceEndedAt(
client.x(), client.y(), root.x(), root.y(),
WebDragOperationNone);
}
return FALSE;
}
void WebDragSourceGtk::OnDragBegin(GtkWidget* sender,
GdkDragContext* drag_context) {
if (!download_url_.is_empty()) {
std::string default_name =
GetContentClient()->browser()->GetDefaultDownloadName();
base::FilePath generated_download_file_name =
net::GenerateFileName(download_url_,
std::string(),
std::string(),
download_file_name_.value(),
base::UTF16ToUTF8(wide_download_mime_type_),
default_name);
gdk_property_change(drag_context->source_window,
ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE),
ui::GetAtomForTarget(ui::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());
}
if (drag_pixbuf_) {
gtk_widget_set_size_request(drag_icon_,
gdk_pixbuf_get_width(drag_pixbuf_),
gdk_pixbuf_get_height(drag_pixbuf_));
if (!gtk_widget_get_realized(drag_icon_)) {
GdkScreen* screen = gtk_widget_get_screen(drag_icon_);
GdkColormap* rgba = gdk_screen_get_rgba_colormap(screen);
if (rgba)
gtk_widget_set_colormap(drag_icon_, rgba);
}
gtk_drag_set_icon_widget(drag_context, drag_icon_,
image_offset_.x(), image_offset_.y());
}
}
void WebDragSourceGtk::OnDragEnd(GtkWidget* sender,
GdkDragContext* drag_context) {
if (drag_pixbuf_) {
g_object_unref(drag_pixbuf_);
drag_pixbuf_ = NULL;
}
if (!download_url_.is_empty()) {
gdk_property_delete(drag_context->source_window,
ui::GetAtomForTarget(ui::DIRECT_SAVE_FILE));
}
if (!drag_failed_) {
gfx::Point root = ui::ScreenPoint(GetContentNativeView());
gfx::Point client = ui::ClientPoint(GetContentNativeView());
if (web_contents_) {
web_contents_->DragSourceEndedAt(
client.x(), client.y(), root.x(), root.y(),
GdkDragActionToWebDragOp(drag_context->action));
}
}
web_contents_->SystemDragEnded();
drop_data_.reset();
drag_context_ = NULL;
}
gfx::NativeView WebDragSourceGtk::GetContentNativeView() const {
return web_contents_->GetView()->GetContentNativeView();
}
gboolean WebDragSourceGtk::OnDragIconExpose(GtkWidget* sender,
GdkEventExpose* event) {
cairo_t* cr = gdk_cairo_create(event->window);
gdk_cairo_rectangle(cr, &event->area);
cairo_clip(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
gdk_cairo_set_source_pixbuf(cr, drag_pixbuf_, 0, 0);
cairo_paint(cr);
cairo_destroy(cr);
return TRUE;
}
}