This source file includes following definitions.
- GetModifierFlags
- method_factory_
- UpdateDragStatus
- DragLeave
- OnDragMotion
- OnDragDataReceived
- OnDragLeave
- OnDragDrop
- GetRenderViewHost
#include "content/browser/web_contents/web_drag_dest_gtk.h"
#include <string>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.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/web_contents_delegate.h"
#include "content/public/browser/web_drag_dest_delegate.h"
#include "content/public/common/url_constants.h"
#include "net/base/net_util.h"
#include "third_party/WebKit/public/web/WebInputEvent.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"
using blink::WebDragOperation;
using blink::WebDragOperationNone;
namespace content {
namespace {
const int kNumGtkHandlers = 5;
int GetModifierFlags(GtkWidget* widget) {
int modifier_state = 0;
GdkModifierType state;
gdk_window_get_pointer(gtk_widget_get_window(widget), NULL, NULL, &state);
if (state & GDK_SHIFT_MASK)
modifier_state |= blink::WebInputEvent::ShiftKey;
if (state & GDK_CONTROL_MASK)
modifier_state |= blink::WebInputEvent::ControlKey;
if (state & GDK_MOD1_MASK)
modifier_state |= blink::WebInputEvent::AltKey;
if (state & GDK_META_MASK)
modifier_state |= blink::WebInputEvent::MetaKey;
return modifier_state;
}
}
WebDragDestGtk::WebDragDestGtk(WebContents* web_contents, GtkWidget* widget)
: web_contents_(web_contents),
widget_(widget),
context_(NULL),
data_requests_(0),
delegate_(NULL),
canceled_(false),
method_factory_(this) {
gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
NULL, 0,
static_cast<GdkDragAction>(GDK_ACTION_COPY |
GDK_ACTION_LINK |
GDK_ACTION_MOVE));
handlers_.reset(new int[kNumGtkHandlers]);
handlers_.get()[0] = g_signal_connect(
widget, "drag-motion", G_CALLBACK(OnDragMotionThunk), this);
handlers_.get()[1] = g_signal_connect(
widget, "drag-leave", G_CALLBACK(OnDragLeaveThunk), this);
handlers_.get()[2] = g_signal_connect(
widget, "drag-drop", G_CALLBACK(OnDragDropThunk), this);
handlers_.get()[3] = g_signal_connect(
widget, "drag-data-received", G_CALLBACK(OnDragDataReceivedThunk), this);
handlers_.get()[4] = g_signal_connect(
widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}
WebDragDestGtk::~WebDragDestGtk() {
if (widget_) {
gtk_drag_dest_unset(widget_);
for (int i = 0; i < kNumGtkHandlers; ++i)
g_signal_handler_disconnect(widget_, handlers_.get()[i]);
}
}
void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
if (context_) {
is_drop_target_ = operation != WebDragOperationNone;
gdk_drag_status(context_, WebDragOpToGdkDragAction(operation),
drag_over_time_);
}
}
void WebDragDestGtk::DragLeave() {
GetRenderViewHost()->DragTargetDragLeave();
if (delegate())
delegate()->OnDragLeave();
drop_data_.reset();
}
gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
GdkDragContext* context,
gint x, gint y,
guint time) {
if (context_ != context) {
context_ = context;
drop_data_.reset(new DropData);
is_drop_target_ = false;
if (delegate())
delegate()->DragInitialize(web_contents_);
static int supported_targets[] = {
ui::RENDERER_TAINT,
ui::TEXT_PLAIN,
ui::TEXT_URI_LIST,
ui::TEXT_HTML,
ui::NETSCAPE_URL,
ui::CHROME_NAMED_URL,
ui::CUSTOM_DATA,
};
data_requests_ = arraysize(supported_targets) + (delegate() ? 1 : 0);
for (size_t i = 0; i < arraysize(supported_targets); ++i) {
gtk_drag_get_data(widget_, context,
ui::GetAtomForTarget(supported_targets[i]),
time);
}
if (delegate()) {
gtk_drag_get_data(widget_, context, delegate()->GetBookmarkTargetAtom(),
time);
}
} else if (data_requests_ == 0) {
if (canceled_)
return FALSE;
GetRenderViewHost()->DragTargetDragOver(
ui::ClientPoint(widget_),
ui::ScreenPoint(widget_),
GdkDragActionToWebDragOp(context->actions),
GetModifierFlags(widget_));
if (delegate())
delegate()->OnDragOver();
drag_over_time_ = time;
}
return TRUE;
}
void WebDragDestGtk::OnDragDataReceived(
GtkWidget* sender, GdkDragContext* context, gint x, gint y,
GtkSelectionData* data, guint info, guint time) {
if (context != context_)
return;
data_requests_--;
gint data_length = gtk_selection_data_get_length(data);
const guchar* raw_data = gtk_selection_data_get_data(data);
GdkAtom target = gtk_selection_data_get_target(data);
if (raw_data && data_length > 0) {
if (target == ui::GetAtomForTarget(ui::RENDERER_TAINT)) {
drop_data_->did_originate_from_renderer = true;
} else if (target == ui::GetAtomForTarget(ui::TEXT_PLAIN)) {
guchar* text = gtk_selection_data_get_text(data);
if (text) {
drop_data_->text = base::NullableString16(
base::UTF8ToUTF16(std::string(reinterpret_cast<const char*>(text))),
false);
g_free(text);
}
} else if (target == ui::GetAtomForTarget(ui::TEXT_URI_LIST)) {
gchar** uris = gtk_selection_data_get_uris(data);
if (uris) {
drop_data_->url = GURL();
for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
GURL url(*uri_iter);
base::FilePath file_path;
if (url.SchemeIs(kFileScheme) &&
net::FileURLToFilePath(url, &file_path)) {
drop_data_->filenames.push_back(
ui::FileInfo(file_path, base::FilePath()));
drop_data_->text = base::NullableString16();
} else if (!drop_data_->url.is_valid()) {
drop_data_->url = url;
}
}
g_strfreev(uris);
}
} else if (target == ui::GetAtomForTarget(ui::TEXT_HTML)) {
drop_data_->html = base::NullableString16(
base::UTF8ToUTF16(std::string(reinterpret_cast<const char*>(raw_data),
data_length)),
false);
} else if (target == ui::GetAtomForTarget(ui::NETSCAPE_URL)) {
std::string netscape_url(reinterpret_cast<const char*>(raw_data),
data_length);
size_t split = netscape_url.find_first_of('\n');
if (split != std::string::npos) {
drop_data_->url = GURL(netscape_url.substr(0, split));
if (split < netscape_url.size() - 1) {
drop_data_->url_title =
base::UTF8ToUTF16(netscape_url.substr(split + 1));
}
}
} else if (target == ui::GetAtomForTarget(ui::CHROME_NAMED_URL)) {
ui::ExtractNamedURL(data, &drop_data_->url, &drop_data_->url_title);
} else if (target == ui::GetAtomForTarget(ui::CUSTOM_DATA)) {
ui::ReadCustomDataIntoMap(
raw_data, data_length, &drop_data_->custom_data);
}
}
if (data_requests_ == 0) {
canceled_ = !web_contents_->GetDelegate()->CanDragEnter(
web_contents_,
*drop_data_,
GdkDragActionToWebDragOp(context->actions));
if (canceled_) {
drag_over_time_ = time;
UpdateDragStatus(WebDragOperationNone);
drop_data_.reset();
return;
}
}
if (delegate() && target == delegate()->GetBookmarkTargetAtom()) {
if (raw_data && data_length > 0) {
delegate()->OnReceiveDataFromGtk(data);
} else {
delegate()->OnReceiveProcessedData(drop_data_->url,
drop_data_->url_title);
}
}
if (data_requests_ == 0) {
GetRenderViewHost()->DragTargetDragEnter(
*drop_data_.get(),
ui::ClientPoint(widget_),
ui::ScreenPoint(widget_),
GdkDragActionToWebDragOp(context->actions),
GetModifierFlags(widget_));
if (delegate())
delegate()->OnDragEnter();
drag_over_time_ = time;
}
}
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
guint time) {
context_ = NULL;
if (canceled_)
return;
if (data_requests_ != 0)
return;
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&WebDragDestGtk::DragLeave, method_factory_.GetWeakPtr()));
}
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
gint x, gint y, guint time) {
method_factory_.InvalidateWeakPtrs();
GetRenderViewHost()->
DragTargetDrop(ui::ClientPoint(widget_), ui::ScreenPoint(widget_),
GetModifierFlags(widget_));
if (delegate())
delegate()->OnDrop();
gtk_drag_finish(context, is_drop_target_, FALSE, time);
return TRUE;
}
RenderViewHostImpl* WebDragDestGtk::GetRenderViewHost() const {
return static_cast<RenderViewHostImpl*>(web_contents_->GetRenderViewHost());
}
}