diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/gtk/tab_contents_drag_source.cc | 216 | ||||
-rw-r--r-- | chrome/browser/gtk/tab_contents_drag_source.h | 85 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_gtk.cc | 214 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_gtk.h | 51 | ||||
-rw-r--r-- | chrome/browser/views/tab_contents/tab_contents_view_gtk.cc | 33 | ||||
-rw-r--r-- | chrome/browser/views/tab_contents/tab_contents_view_gtk.h | 8 | ||||
-rw-r--r-- | chrome/chrome.gyp | 4 | ||||
-rw-r--r-- | chrome/common/gtk_util.cc | 13 | ||||
-rw-r--r-- | chrome/common/gtk_util.h | 6 |
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_ |