summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/gtk/tab_contents_drag_source.cc216
-rw-r--r--chrome/browser/gtk/tab_contents_drag_source.h85
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.cc214
-rw-r--r--chrome/browser/tab_contents/tab_contents_view_gtk.h51
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_gtk.cc33
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_gtk.h8
-rw-r--r--chrome/chrome.gyp4
-rw-r--r--chrome/common/gtk_util.cc13
-rw-r--r--chrome/common/gtk_util.h6
9 files changed, 359 insertions, 271 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();
+}
diff --git a/chrome/browser/gtk/tab_contents_drag_source.h b/chrome/browser/gtk/tab_contents_drag_source.h
new file mode 100644
index 0000000..1d35669
--- /dev/null
+++ b/chrome/browser/gtk/tab_contents_drag_source.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef CHROME_BROWSER_GTK_TAB_CONTENTS_DRAG_SOURCE_H_
+#define CHROME_BROWSER_GTK_TAB_CONTENTS_DRAG_SOURCE_H_
+
+#include <gtk/gtk.h>
+
+#include "base/basictypes.h"
+#include "base/gfx/native_widget_types.h"
+#include "base/message_loop.h"
+
+class TabContents;
+class TabContentsView;
+struct WebDropData;
+
+// TabContentsDragSource takes care of managing the drag from a TabContents
+// with Gtk.
+class TabContentsDragSource : public MessageLoopForUI::Observer {
+ public:
+ explicit TabContentsDragSource(TabContentsView* tab_contents_view);
+ ~TabContentsDragSource();
+
+ TabContents* tab_contents() const;
+
+ // Starts a drag for the tab contents this TabContentsDragSource was
+ // created for.
+ void StartDragging(const WebDropData& drop_data,
+ GdkEventButton* last_mouse_down);
+
+ // MessageLoop::Observer implementation:
+ virtual void WillProcessEvent(GdkEvent* event);
+ virtual void DidProcessEvent(GdkEvent* event);
+
+ private:
+ static gboolean OnDragFailedThunk(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ GtkDragResult result,
+ TabContentsDragSource* handler) {
+ return handler->OnDragFailed();
+ }
+ gboolean OnDragFailed();
+ static void OnDragEndThunk(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ TabContentsDragSource* handler) {
+ handler->OnDragEnd();
+ }
+ void OnDragEnd();
+ static void OnDragDataGetThunk(GtkWidget* drag_widget,
+ GdkDragContext* context,
+ GtkSelectionData* selection_data,
+ guint target_type,
+ guint time,
+ TabContentsDragSource* handler) {
+ handler->OnDragDataGet(context, selection_data, target_type, time);
+ }
+ void OnDragDataGet(GdkDragContext* context, GtkSelectionData* selection_data,
+ guint target_type, guint time);
+
+ gfx::NativeView GetContentNativeView() const;
+
+ // The view we're manging the drag for.
+ TabContentsView* tab_contents_view_;
+
+ // The drop data for the current drag (for drags that originate in the render
+ // view). Non-NULL iff there is a current drag.
+ scoped_ptr<WebDropData> drop_data_;
+
+ // The mime type for the file contents of the current drag (if any).
+ GdkAtom drag_file_mime_type_;
+
+ // Whether the current drag has failed. Meaningless if we are not the source
+ // for a current drag.
+ bool drag_failed_;
+
+ // This is the widget we use to initiate drags. Since we don't use the
+ // renderer widget, we can persist drags even when our contents is switched
+ // out.
+ GtkWidget* drag_widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabContentsDragSource);
+};
+
+#endif // CHROME_BROWSER_GTK_TAB_CONTENTS_DRAG_SOURCE_H_
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
index fca9efa..9bb7036 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc
@@ -8,7 +8,6 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#include "base/mime_util.h"
#include "base/gfx/point.h"
#include "base/gfx/rect.h"
#include "base/gfx/size.h"
@@ -23,6 +22,7 @@
#include "chrome/browser/gtk/gtk_floating_container.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/sad_tab_gtk.h"
+#include "chrome/browser/gtk/tab_contents_drag_source.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
@@ -189,21 +189,6 @@ int GdkEventKeyToLayoutIndependentKeyval(const GdkEventKey* event) {
return event->keyval;
}
-// Get the current location of the mouse cursor relative to the screen.
-gfx::Point ScreenPoint(GtkWidget* widget) {
- int x, y;
- gdk_display_get_pointer(gtk_widget_get_display(widget), NULL, &x, &y,
- NULL);
- return gfx::Point(x, y);
-}
-
-// Get the current location of the mouse cursor relative to the widget.
-gfx::Point ClientPoint(GtkWidget* widget) {
- int x, y;
- gtk_widget_get_pointer(widget, &x, &y);
- return gfx::Point(x, y);
-}
-
} // namespace
// A helper class that handles DnD for drops in the renderer. In GTK parlance,
@@ -302,7 +287,8 @@ class WebDragDest {
}
} else if (data_requests_ == 0) {
tab_contents_->render_view_host()->
- DragTargetDragOver(ClientPoint(widget_), ScreenPoint(widget_));
+ DragTargetDragOver(gtk_util::ClientPoint(widget_),
+ gtk_util::ScreenPoint(widget_));
drag_over_time_ = time;
}
@@ -364,7 +350,8 @@ class WebDragDest {
// |x| and |y| are seemingly arbitrary at this point.
tab_contents_->render_view_host()->
DragTargetDragEnter(*drop_data_.get(),
- ClientPoint(widget_), ScreenPoint(widget_));
+ gtk_util::ClientPoint(widget_),
+ gtk_util::ScreenPoint(widget_));
drag_over_time_ = time;
}
}
@@ -389,7 +376,8 @@ class WebDragDest {
method_factory_.RevokeAll();
tab_contents_->render_view_host()->
- DragTargetDrop(ClientPoint(widget_), ScreenPoint(widget_));
+ DragTargetDrop(gtk_util::ClientPoint(widget_),
+ gtk_util::ScreenPoint(widget_));
// The second parameter is just an educated guess, but at least we will
// get the drag-end animation right sometimes.
@@ -437,9 +425,7 @@ TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents)
: TabContentsView(tab_contents),
floating_(gtk_floating_container_new()),
fixed_(gtk_fixed_new()),
- popup_view_(NULL),
- drag_failed_(false),
- drag_widget_(NULL) {
+ popup_view_(NULL) {
g_signal_connect(fixed_, "size-allocate",
G_CALLBACK(OnSizeAllocate), this);
g_signal_connect(floating_.get(), "set-floating-position",
@@ -450,15 +436,7 @@ TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents)
gtk_widget_show(floating_.get());
registrar_.Add(this, NotificationType::TAB_CONTENTS_CONNECTED,
Source<TabContents>(tab_contents));
-
- // Renderer source DnD.
- 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_);
+ drag_source_.reset(new TabContentsDragSource(this));
}
TabContentsViewGtk::~TabContentsViewGtk() {
@@ -577,24 +555,7 @@ void TabContentsViewGtk::GetContainerBounds(gfx::Rect* out) const {
void TabContentsViewGtk::OnContentsDestroy() {
// We don't want to try to handle drag events from this point on.
- 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;
+ drag_source_.reset();
}
void TabContentsViewGtk::SetPageTitle(const std::wstring& title) {
@@ -704,23 +665,6 @@ void TabContentsViewGtk::Observe(NotificationType type,
}
}
-void TabContentsViewGtk::WillProcessEvent(GdkEvent* event) {
- // No-op.
-}
-
-void TabContentsViewGtk::DidProcessEvent(GdkEvent* event) {
- if (event->type != GDK_MOTION_NOTIFY)
- return;
-
- GdkEventMotion* event_motion = reinterpret_cast<GdkEventMotion*>(event);
- gfx::Point client = 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 TabContentsViewGtk::ShowContextMenu(const ContextMenuParams& params) {
context_menu_.reset(new RenderViewContextMenuGtk(tab_contents(), params,
last_mouse_down_.time));
@@ -733,143 +677,7 @@ void TabContentsViewGtk::ShowContextMenu(const ContextMenuParams& params) {
void TabContentsViewGtk::StartDragging(const WebDropData& drop_data) {
DCHECK(GetContentNativeView());
- 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 TabContentsViewGtk::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 TabContentsViewGtk::OnDragFailed() {
- drag_failed_ = true;
-
- gfx::Point root = ScreenPoint(GetContentNativeView());
- gfx::Point client = 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 TabContentsViewGtk::OnDragEnd() {
- MessageLoopForUI::current()->RemoveObserver(this);
-
- if (!drag_failed_) {
- gfx::Point root = ScreenPoint(GetContentNativeView());
- gfx::Point client = 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();
+ drag_source_->StartDragging(drop_data, &last_mouse_down_);
}
// -----------------------------------------------------------------------------
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h
index 1118cc3..e63e346 100644
--- a/chrome/browser/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h
@@ -9,7 +9,6 @@
#include <vector>
-#include "base/message_loop.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/gtk/focus_store_gtk.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
@@ -22,12 +21,12 @@ class ConstrainedWindowGtk;
class GtkThemeProperties;
class RenderViewContextMenuGtk;
class SadTabGtk;
+class TabContentsDragSource;
class WebDragDest;
typedef struct _GtkFloatingContainer GtkFloatingContainer;
class TabContentsViewGtk : public TabContentsView,
- public NotificationObserver,
- public MessageLoopForUI::Observer {
+ public NotificationObserver {
public:
// The corresponding TabContents is passed in the constructor, and manages our
// lifetime. This doesn't need to be the case, but is this way currently
@@ -79,12 +78,6 @@ class TabContentsViewGtk : public TabContentsView,
const NotificationSource& source,
const NotificationDetails& details);
-
- protected:
- // MessageLoop::Observer implementation:
- virtual void WillProcessEvent(GdkEvent* event);
- virtual void DidProcessEvent(GdkEvent* event);
-
private:
// Insert the given widget into the content area. Should only be used for
// web pages and the like (including interstitials and sad tab). Note that
@@ -107,31 +100,6 @@ class TabContentsViewGtk : public TabContentsView,
GtkFloatingContainer* floating_container, GtkAllocation* allocation,
TabContentsViewGtk* tab_contents_view);
- // Webkit source-side DnD.
- static gboolean OnDragFailedThunk(GtkWidget* widget,
- GdkDragContext* drag_context,
- GtkDragResult result,
- TabContentsViewGtk* view) {
- return view->OnDragFailed();
- }
- gboolean OnDragFailed();
- static void OnDragEndThunk(GtkWidget* widget,
- GdkDragContext* drag_context,
- TabContentsViewGtk* view) {
- view->OnDragEnd();
- }
- void OnDragEnd();
- static void OnDragDataGetThunk(GtkWidget* drag_widget,
- GdkDragContext* context,
- GtkSelectionData* selection_data,
- guint target_type,
- guint time,
- TabContentsViewGtk* view) {
- view->OnDragDataGet(context, selection_data, target_type, time);
- }
- void OnDragDataGet(GdkDragContext* context, GtkSelectionData* selection_data,
- guint target_type, guint time);
-
// Contains |fixed_| as its GtkBin member and a possible floating widget from
// |popup_view_|.
OwnedWidgetGtk floating_;
@@ -163,21 +131,12 @@ class TabContentsViewGtk : public TabContentsView,
// objects in this vector are owned by the TabContents, not the view.
std::vector<ConstrainedWindowGtk*> constrained_windows_;
- // The drop data for the current drag (for drags that originate in the render
- // view). Non-NULL iff there is a current drag.
- scoped_ptr<WebDropData> drop_data_;
- // The mime type for the file contents of the current drag (if any).
- GdkAtom drag_file_mime_type_;
// The helper object that handles drag destination related interactions with
// GTK.
scoped_ptr<WebDragDest> drag_dest_;
- // Whether the current drag has failed. Meaningless if we are not the source
- // for a current drag.
- bool drag_failed_;
- // This is the widget we use to initiate drags. Since we don't use the
- // renderer widget, we can persist drags even when our contents is switched
- // out.
- GtkWidget* drag_widget_;
+
+ // Object responsible for handling drags from the page for us.
+ scoped_ptr<TabContentsDragSource> drag_source_;
DISALLOW_COPY_AND_ASSIGN(TabContentsViewGtk);
};
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
index e2ad712..54f22b4 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
+++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
@@ -14,6 +14,7 @@
#include "build/build_config.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/gtk/tab_contents_drag_source.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
@@ -93,6 +94,7 @@ TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents)
: TabContentsView(tab_contents),
views::WidgetGtk(TYPE_CHILD),
ignore_next_char_event_(false) {
+ drag_source_.reset(new TabContentsDragSource(this));
}
TabContentsViewGtk::~TabContentsViewGtk() {
@@ -159,14 +161,7 @@ void TabContentsViewGtk::GetContainerBounds(gfx::Rect* out) const {
}
void TabContentsViewGtk::StartDragging(const WebDropData& drop_data) {
- NOTIMPLEMENTED();
-
- // Until we have d'n'd implemented, just immediately pretend we're
- // already done with the drag and drop so we don't get stuck
- // thinking we're in mid-drag.
- // TODO(port): remove me when the above NOTIMPLEMENTED is fixed.
- if (tab_contents()->render_view_host())
- tab_contents()->render_view_host()->DragSourceSystemDragEnded();
+ drag_source_->StartDragging(drop_data, &last_mouse_down_);
}
void TabContentsViewGtk::OnContentsDestroy() {
@@ -175,20 +170,8 @@ void TabContentsViewGtk::OnContentsDestroy() {
// can be moved into OnDestroy which is a Windows message handler as the
// window is being torn down.
- // When a tab is closed all its child plugin windows are destroyed
- // automatically. This happens before plugins get any notification that its
- // instances are tearing down.
- //
- // Plugins like Quicktime assume that their windows will remain valid as long
- // as they have plugin instances active. Quicktime crashes in this case
- // because its windowing code cleans up an internal data structure that the
- // handler for NPP_DestroyStream relies on.
- //
- // The fix is to detach plugin windows from web contents when it is going
- // away. This will prevent the plugin windows from getting destroyed
- // automatically. The detached plugin windows will get cleaned up in proper
- // sequence as part of the usual cleanup when the plugin instance goes away.
- NOTIMPLEMENTED();
+ // We don't want to try to handle drag events from this point on.
+ drag_source_.reset();
}
void TabContentsViewGtk::SetPageTitle(const std::wstring& title) {
@@ -279,6 +262,12 @@ void TabContentsViewGtk::ShowContextMenu(const ContextMenuParams& params) {
MessageLoop::current()->SetNestableTasksAllowed(old_state);
}
+gboolean TabContentsViewGtk::OnButtonPress(GtkWidget* widget,
+ GdkEventButton* event) {
+ last_mouse_down_ = *event;
+ return views::WidgetGtk::OnButtonPress(widget, event);
+}
+
void TabContentsViewGtk::OnSizeAllocate(GtkWidget* widget,
GtkAllocation* allocation) {
WasSized(gfx::Size(allocation->width, allocation->height));
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
index 900fecc..561267b 100644
--- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
+++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
@@ -12,6 +12,7 @@
class RenderViewContextMenuWin;
class SadTabView;
+class TabContentsDragSource;
namespace views {
class NativeViewHost;
}
@@ -58,6 +59,7 @@ class TabContentsViewGtk : public TabContentsView,
// Signal handlers -----------------------------------------------------------
// Overridden from views::WidgetGtk:
+ virtual gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event);
virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation);
// Handles notifying the TabContents and other operations when the window was
@@ -81,6 +83,12 @@ class TabContentsViewGtk : public TabContentsView,
// The context menu. Callbacks are asynchronous so we need to keep it around.
scoped_ptr<RenderViewContextMenuWin> context_menu_;
+ // Handles drags from this TabContentsView.
+ scoped_ptr<TabContentsDragSource> drag_source_;
+
+ // The event for the last mouse down we handled. We need this for drags.
+ GdkEventButton last_mouse_down_;
+
DISALLOW_COPY_AND_ASSIGN(TabContentsViewGtk);
};
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 3f1c739..5328ea4 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1204,6 +1204,8 @@
'browser/gtk/status_bubble_gtk.h',
'browser/gtk/tab_contents_container_gtk.cc',
'browser/gtk/tab_contents_container_gtk.h',
+ 'browser/gtk/tab_contents_drag_source.cc',
+ 'browser/gtk/tab_contents_drag_source.h',
'browser/gtk/tabs/dragged_tab_controller_gtk.cc',
'browser/gtk/tabs/dragged_tab_controller_gtk.h',
'browser/gtk/tabs/dragged_tab_gtk.cc',
@@ -2368,6 +2370,8 @@
['include', '^browser/gtk/list_store_favicon_loader.h'],
['include', '^browser/gtk/menu_gtk.cc'],
['include', '^browser/gtk/menu_gtk.h'],
+ ['include', '^browser/gtk/tab_contents_drag_source.cc'],
+ ['include', '^browser/gtk/tab_contents_drag_source.h'],
# Other excluded stuff.
['exclude', '^browser/autocomplete/autocomplete_popup_view_gtk.cc'],
diff --git a/chrome/common/gtk_util.cc b/chrome/common/gtk_util.cc
index 08658a7..c97a3a5 100644
--- a/chrome/common/gtk_util.cc
+++ b/chrome/common/gtk_util.cc
@@ -488,4 +488,17 @@ void InitRendererPrefsFromGtkSettings(RendererPreferences* prefs) {
g_free(rgba_style);
}
+gfx::Point ScreenPoint(GtkWidget* widget) {
+ int x, y;
+ gdk_display_get_pointer(gtk_widget_get_display(widget), NULL, &x, &y,
+ NULL);
+ return gfx::Point(x, y);
+}
+
+gfx::Point ClientPoint(GtkWidget* widget) {
+ int x, y;
+ gtk_widget_get_pointer(widget, &x, &y);
+ return gfx::Point(x, y);
+}
+
} // namespace gtk_util
diff --git a/chrome/common/gtk_util.h b/chrome/common/gtk_util.h
index 786c5a3..867dbc5 100644
--- a/chrome/common/gtk_util.h
+++ b/chrome/common/gtk_util.h
@@ -150,6 +150,12 @@ GtkWidget* IndentWidget(GtkWidget* content);
// based on GtkSettings (which itself comes from XSETTINGS).
void InitRendererPrefsFromGtkSettings(RendererPreferences* prefs);
+// Get the current location of the mouse cursor relative to the screen.
+gfx::Point ScreenPoint(GtkWidget* widget);
+
+// Get the current location of the mouse cursor relative to the widget.
+gfx::Point ClientPoint(GtkWidget* widget);
+
} // namespace gtk_util
#endif // CHROME_COMMON_GTK_UTIL_H_