diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-12 04:03:27 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-12 04:03:27 +0000 |
commit | 5c7c41ad79c21366a9a27b4fea114b2ebf8fbc58 (patch) | |
tree | 4f8becf0d748f502f9b6932d91768bc066ec0144 /chrome/browser/gtk/tab_contents_drag_source.cc | |
parent | c0d769d16ca94f36239fcd82725d909947f1cc1c (diff) | |
download | chromium_src-5c7c41ad79c21366a9a27b4fea114b2ebf8fbc58.zip chromium_src-5c7c41ad79c21366a9a27b4fea114b2ebf8fbc58.tar.gz chromium_src-5c7c41ad79c21366a9a27b4fea114b2ebf8fbc58.tar.bz2 |
Refactors drag support from TabContentsViewGtk into
TabContentsDragHandler so that it can be used by both Gtk and Views.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/165302
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23168 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk/tab_contents_drag_source.cc')
-rw-r--r-- | chrome/browser/gtk/tab_contents_drag_source.cc | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/chrome/browser/gtk/tab_contents_drag_source.cc b/chrome/browser/gtk/tab_contents_drag_source.cc new file mode 100644 index 0000000..639795b --- /dev/null +++ b/chrome/browser/gtk/tab_contents_drag_source.cc @@ -0,0 +1,216 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/gtk/tab_contents_drag_source.h" + +#include "base/mime_util.h" +#include "chrome/browser/gtk/gtk_dnd_util.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 "webkit/glue/webdropdata.h" + +TabContentsDragSource::TabContentsDragSource( + TabContentsView* tab_contents_view) + : tab_contents_view_(tab_contents_view), + drag_failed_(false), + drag_widget_(NULL) { + drag_widget_ = gtk_invisible_new(); + g_signal_connect(drag_widget_, "drag-failed", + G_CALLBACK(OnDragFailedThunk), this); + g_signal_connect(drag_widget_, "drag-end", G_CALLBACK(OnDragEndThunk), this); + g_signal_connect(drag_widget_, "drag-data-get", + G_CALLBACK(OnDragDataGetThunk), this); + g_object_ref_sink(drag_widget_); +} + +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>(OnDragEndThunk), this); + g_signal_handlers_disconnect_by_func(drag_widget_, + reinterpret_cast<gpointer>(OnDragDataGetThunk), this); + + // Break the current drag, if any. + if (drop_data_.get()) { + gtk_grab_add(drag_widget_); + gtk_grab_remove(drag_widget_); + MessageLoopForUI::current()->RemoveObserver(this); + drop_data_.reset(); + } + + gtk_widget_destroy(drag_widget_); + g_object_unref(drag_widget_); + drag_widget_ = NULL; +} + +TabContents* TabContentsDragSource::tab_contents() const { + return tab_contents_view_->tab_contents(); +} + +void TabContentsDragSource::StartDragging(const WebDropData& drop_data, + GdkEventButton* last_mouse_down) { + int targets_mask = 0; + + if (!drop_data.plain_text.empty()) + targets_mask |= GtkDndUtil::TEXT_PLAIN; + if (drop_data.url.is_valid()) { + targets_mask |= GtkDndUtil::TEXT_URI_LIST; + targets_mask |= GtkDndUtil::CHROME_NAMED_URL; + } + if (!drop_data.text_html.empty()) + targets_mask |= GtkDndUtil::TEXT_HTML; + if (!drop_data.file_contents.empty()) + targets_mask |= GtkDndUtil::CHROME_WEBDROP_FILE_CONTENTS; + + if (targets_mask == 0) { + NOTIMPLEMENTED(); + if (tab_contents()->render_view_host()) + tab_contents()->render_view_host()->DragSourceSystemDragEnded(); + } + + drop_data_.reset(new WebDropData(drop_data)); + + GtkTargetList* list = GtkDndUtil::GetTargetListFromCodeMask(targets_mask); + if (targets_mask & GtkDndUtil::CHROME_WEBDROP_FILE_CONTENTS) { + drag_file_mime_type_ = gdk_atom_intern( + mime_util::GetDataMimeType(drop_data.file_contents).c_str(), FALSE); + gtk_target_list_add(list, drag_file_mime_type_, + 0, GtkDndUtil::CHROME_WEBDROP_FILE_CONTENTS); + } + + drag_failed_ = false; + // If we don't pass an event, GDK won't know what event time to start grabbing + // mouse events. Technically it's the mouse motion event and not the mouse + // down event that causes the drag, but there's no reliable way to know + // *which* motion event initiated the drag, so this will have to do. + // TODO(estade): This can sometimes be very far off, e.g. if the user clicks + // and holds and doesn't start dragging for a long time. I doubt it matters + // much, but we should probably look into the possibility of getting the + // initiating event from webkit. + gtk_drag_begin(drag_widget_, list, GDK_ACTION_COPY, + 1, // Drags are always initiated by the left button. + reinterpret_cast<GdkEvent*>(last_mouse_down)); + MessageLoopForUI::current()->AddObserver(this); + // The drag adds a ref; let it own the list. + gtk_target_list_unref(list); +} + +void TabContentsDragSource::WillProcessEvent(GdkEvent* event) { + // No-op. +} + +void TabContentsDragSource::DidProcessEvent(GdkEvent* event) { + if (event->type != GDK_MOTION_NOTIFY) + return; + + GdkEventMotion* event_motion = reinterpret_cast<GdkEventMotion*>(event); + gfx::Point client = gtk_util::ClientPoint(GetContentNativeView()); + + if (tab_contents()->render_view_host()) { + tab_contents()->render_view_host()->DragSourceMovedTo( + client.x(), client.y(), event_motion->x_root, event_motion->y_root); + } +} + +void TabContentsDragSource::OnDragDataGet( + GdkDragContext* context, GtkSelectionData* selection_data, + guint target_type, guint time) { + const int bits_per_byte = 8; + + switch (target_type) { + case GtkDndUtil::TEXT_PLAIN: { + std::string utf8_text = UTF16ToUTF8(drop_data_->plain_text); + gtk_selection_data_set_text(selection_data, utf8_text.c_str(), + utf8_text.length()); + break; + } + + case GtkDndUtil::TEXT_URI_LIST: { + gchar* uri_array[2]; + uri_array[0] = strdup(drop_data_->url.spec().c_str()); + uri_array[1] = NULL; + gtk_selection_data_set_uris(selection_data, uri_array); + free(uri_array[0]); + break; + } + + case GtkDndUtil::TEXT_HTML: { + // TODO(estade): change relative links to be absolute using + // |html_base_url|. + std::string utf8_text = UTF16ToUTF8(drop_data_->text_html); + gtk_selection_data_set(selection_data, + GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_HTML), + bits_per_byte, + reinterpret_cast<const guchar*>(utf8_text.c_str()), + utf8_text.length()); + break; + } + + case GtkDndUtil::CHROME_NAMED_URL: { + Pickle pickle; + pickle.WriteString(UTF16ToUTF8(drop_data_->url_title)); + pickle.WriteString(drop_data_->url.spec()); + gtk_selection_data_set( + selection_data, + GtkDndUtil::GetAtomForTarget(GtkDndUtil::CHROME_NAMED_URL), + bits_per_byte, + reinterpret_cast<const guchar*>(pickle.data()), + pickle.size()); + break; + } + + case GtkDndUtil::CHROME_WEBDROP_FILE_CONTENTS: { + gtk_selection_data_set( + selection_data, + drag_file_mime_type_, bits_per_byte, + reinterpret_cast<const guchar*>(drop_data_->file_contents.data()), + drop_data_->file_contents.length()); + break; + } + + default: + NOTREACHED(); + } +} + +gboolean TabContentsDragSource::OnDragFailed() { + drag_failed_ = true; + + gfx::Point root = gtk_util::ScreenPoint(GetContentNativeView()); + gfx::Point client = gtk_util::ClientPoint(GetContentNativeView()); + + if (tab_contents()->render_view_host()) { + tab_contents()->render_view_host()->DragSourceCancelledAt( + client.x(), client.y(), root.x(), root.y()); + } + + // Let the native failure animation run. + return FALSE; +} + +void TabContentsDragSource::OnDragEnd() { + MessageLoopForUI::current()->RemoveObserver(this); + + if (!drag_failed_) { + gfx::Point root = gtk_util::ScreenPoint(GetContentNativeView()); + gfx::Point client = gtk_util::ClientPoint(GetContentNativeView()); + + if (tab_contents()->render_view_host()) { + tab_contents()->render_view_host()->DragSourceEndedAt( + client.x(), client.y(), root.x(), root.y()); + } + } + + if (tab_contents()->render_view_host()) + tab_contents()->render_view_host()->DragSourceSystemDragEnded(); + + drop_data_.reset(); +} + +gfx::NativeView TabContentsDragSource::GetContentNativeView() const { + return tab_contents_view_->GetContentNativeView(); +} |