diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 21:49:16 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 21:49:16 +0000 |
commit | 0d726c521db7f2f456e04223ef71a1c8c28764f1 (patch) | |
tree | 2c6bcde57b5b98ca38bd337ccbea08dc9f9d6f74 /chrome/browser/tab_contents | |
parent | 4a99e834fe351c8e81a70ea571d52b3cdde40af1 (diff) | |
download | chromium_src-0d726c521db7f2f456e04223ef71a1c8c28764f1.zip chromium_src-0d726c521db7f2f456e04223ef71a1c8c28764f1.tar.gz chromium_src-0d726c521db7f2f456e04223ef71a1c8c28764f1.tar.bz2 |
Pulls WebDragDest out of TabContentsViewGtk so that it can be used by
both views and gtk.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/265041
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28457 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/tab_contents')
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_gtk.cc | 235 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_gtk.h | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_drag_dest_gtk.cc | 180 | ||||
-rw-r--r-- | chrome/browser/tab_contents/web_drag_dest_gtk.h | 105 |
4 files changed, 289 insertions, 235 deletions
diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc index 7a70a28..b738b8a 100644 --- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc @@ -30,6 +30,7 @@ #include "chrome/browser/tab_contents/render_view_context_menu_gtk.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" +#include "chrome/browser/tab_contents/web_drag_dest_gtk.h" #include "chrome/common/gtk_util.h" #include "chrome/common/notification_service.h" #include "chrome/common/notification_source.h" @@ -37,8 +38,6 @@ #include "webkit/glue/webdropdata.h" using WebKit::WebDragOperation; -using WebKit::WebDragOperationCopy; -using WebKit::WebDragOperationNone; using WebKit::WebDragOperationsMask; namespace { @@ -111,236 +110,6 @@ void SetSizeRequest(GtkWidget* widget, gpointer userdata) { } // namespace -// A helper class that handles DnD for drops in the renderer. In GTK parlance, -// this handles destination-side DnD, but not source-side DnD. -class WebDragDest { - public: - explicit WebDragDest(TabContents* tab_contents, GtkWidget* widget) - : tab_contents_(tab_contents), - widget_(widget), - context_(NULL), - method_factory_(this) { - gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0), - NULL, 0, GDK_ACTION_COPY); - g_signal_connect(widget, "drag-motion", - G_CALLBACK(OnDragMotionThunk), this); - g_signal_connect(widget, "drag-leave", - G_CALLBACK(OnDragLeaveThunk), this); - g_signal_connect(widget, "drag-drop", - G_CALLBACK(OnDragDropThunk), this); - g_signal_connect(widget, "drag-data-received", - G_CALLBACK(OnDragDataReceivedThunk), this); - - destroy_handler_ = g_signal_connect(widget, "destroy", - G_CALLBACK(gtk_widget_destroyed), &widget_); - } - - ~WebDragDest() { - if (widget_) { - gtk_drag_dest_unset(widget_); - g_signal_handler_disconnect(widget_, destroy_handler_); - } - } - - // This is called when the renderer responds to a drag motion event. We must - // update the system drag cursor. - void UpdateDragStatus(WebDragOperation operation) { - if (context_) { - // TODO(estade): we might want to support other actions besides copy, - // but that would increase the cost of getting our drag success guess - // wrong. - is_drop_target_ = operation != WebDragOperationNone; - // TODO(snej): Pass appropriate GDK action instead of hardcoding COPY - gdk_drag_status(context_, is_drop_target_ ? GDK_ACTION_COPY : - static_cast<GdkDragAction>(0), - drag_over_time_); - } - } - - // Informs the renderer when a system drag has left the render view. - // See OnDragLeave(). - void DragLeave() { - tab_contents_->render_view_host()->DragTargetDragLeave(); - } - - private: - static gboolean OnDragMotionThunk(GtkWidget* widget, - GdkDragContext* drag_context, gint x, gint y, guint time, - WebDragDest* dest) { - return dest->OnDragMotion(drag_context, x, y, time); - } - static void OnDragLeaveThunk(GtkWidget* widget, - GdkDragContext* drag_context, guint time, WebDragDest* dest) { - dest->OnDragLeave(drag_context, time); - } - static gboolean OnDragDropThunk(GtkWidget* widget, - GdkDragContext* drag_context, gint x, gint y, guint time, - WebDragDest* dest) { - return dest->OnDragDrop(drag_context, x, y, time); - } - static void OnDragDataReceivedThunk(GtkWidget* widget, - GdkDragContext* drag_context, gint x, gint y, - GtkSelectionData* data, guint info, guint time, WebDragDest* dest) { - dest->OnDragDataReceived(drag_context, x, y, data, info, time); - } - - // Called when a system drag crosses over the render view. As there is no drag - // enter event, we treat it as an enter event (and not a regular motion event) - // when |context_| is NULL. - gboolean OnDragMotion(GdkDragContext* context, gint x, gint y, guint time) { - if (context_ != context) { - context_ = context; - drop_data_.reset(new WebDropData); - is_drop_target_ = false; - - static int supported_targets[] = { - GtkDndUtil::TEXT_PLAIN, - GtkDndUtil::TEXT_URI_LIST, - GtkDndUtil::TEXT_HTML, - // TODO(estade): support image drags? - }; - - data_requests_ = arraysize(supported_targets); - for (size_t i = 0; i < arraysize(supported_targets); ++i) { - gtk_drag_get_data(widget_, context, - GtkDndUtil::GetAtomForTarget(supported_targets[i]), - time); - } - } else if (data_requests_ == 0) { - tab_contents_->render_view_host()-> - DragTargetDragOver(gtk_util::ClientPoint(widget_), - gtk_util::ScreenPoint(widget_), - WebDragOperationCopy); - // TODO(snej): Pass appropriate DragOperation instead of hardcoding - drag_over_time_ = time; - } - - // Pretend we are a drag destination because we don't want to wait for - // the renderer to tell us if we really are or not. - return TRUE; - } - - // We make a series of requests for the drag data when the drag first enters - // the render view. This is the callback that is used to give us the data - // for each individual target. When |data_requests_| reaches 0, we know we - // have attained all the data, and we can finally tell the renderer about the - // drag. - void OnDragDataReceived(GdkDragContext* context, gint x, gint y, - GtkSelectionData* data, guint info, guint time) { - // We might get the data from an old get_data() request that we no longer - // care about. - if (context != context_) - return; - - data_requests_--; - - // Decode the data. - if (data->data) { - // If the source can't provide us with valid data for a requested target, - // data->data will be NULL. - if (data->target == - GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_PLAIN)) { - guchar* text = gtk_selection_data_get_text(data); - if (text) { - drop_data_->plain_text = UTF8ToUTF16(std::string( - reinterpret_cast<char*>(text), data->length)); - g_free(text); - } - } else if (data->target == - GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_URI_LIST)) { - gchar** uris = gtk_selection_data_get_uris(data); - if (uris) { - for (gchar** uri_iter = uris; *uri_iter; uri_iter++) { - // TODO(estade): Can the filenames have a non-UTF8 encoding? - drop_data_->filenames.push_back(UTF8ToUTF16(*uri_iter)); - } - // Also, write the first URI as the URL. - if (uris[0]) - drop_data_->url = GURL(uris[0]); - g_strfreev(uris); - } - } else if (data->target == - GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_HTML)) { - // TODO(estade): Can the html have a non-UTF8 encoding? - drop_data_->text_html = UTF8ToUTF16(std::string( - reinterpret_cast<char*>(data->data), data->length)); - // We leave the base URL empty. - } - } - - if (data_requests_ == 0) { - // Tell the renderer about the drag. - // |x| and |y| are seemingly arbitrary at this point. - tab_contents_->render_view_host()-> - DragTargetDragEnter(*drop_data_.get(), - gtk_util::ClientPoint(widget_), - gtk_util::ScreenPoint(widget_), - WebDragOperationCopy); - // TODO(snej): Pass appropriate DragOperation instead of hardcoding - drag_over_time_ = time; - } - } - - // The drag has left our widget; forward this information to the renderer. - void OnDragLeave(GdkDragContext* context, guint time) { - // Set |context_| to NULL to make sure we will recognize the next DragMotion - // as an enter. - context_ = NULL; - drop_data_.reset(); - // When GTK sends us a drag-drop signal, it is shortly (and synchronously) - // preceded by a drag-leave. The renderer doesn't like getting the signals - // in this order so delay telling it about the drag-leave till we are sure - // we are not getting a drop as well. - MessageLoop::current()->PostTask(FROM_HERE, - method_factory_.NewRunnableMethod(&WebDragDest::DragLeave)); - } - - // Called by GTK when the user releases the mouse, executing a drop. - gboolean OnDragDrop(GdkDragContext* context, gint x, gint y, guint time) { - // Cancel that drag leave! - method_factory_.RevokeAll(); - - tab_contents_->render_view_host()-> - 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. - gtk_drag_finish(context, is_drop_target_, FALSE, time); - return TRUE; - } - - - TabContents* tab_contents_; - // The render view. - GtkWidget* widget_; - // The current drag context for system drags over our render view, or NULL if - // there is no system drag or the system drag is not over our render view. - GdkDragContext* context_; - // The data for the current drag, or NULL if |context_| is NULL. - scoped_ptr<WebDropData> drop_data_; - - // The number of outstanding drag data requests we have sent to the drag - // source. - int data_requests_; - - // The last time we sent a message to the renderer related to a drag motion. - gint drag_over_time_; - - // Whether the cursor is over a drop target, according to the last message we - // got from the renderer. - bool is_drop_target_; - - // Handler ID for the destroy signal handler. We connect to the destroy - // signal handler so that we won't call dest_unset on it after it is - // destroyed, but we have to cancel the handler if we are destroyed before - // |widget_| is. - int destroy_handler_; - - ScopedRunnableMethodFactory<WebDragDest> method_factory_; - DISALLOW_COPY_AND_ASSIGN(WebDragDest); -}; - // static TabContentsView* TabContentsView::Create(TabContents* tab_contents) { return new TabContentsViewGtk(tab_contents); @@ -443,7 +212,7 @@ RenderWidgetHostView* TabContentsViewGtk::CreateViewForWidget( InsertIntoContentArea(content_view); // Renderer target DnD. - drag_dest_.reset(new WebDragDest(tab_contents(), content_view)); + drag_dest_.reset(new WebDragDestGtk(tab_contents(), content_view)); return view; } diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.h b/chrome/browser/tab_contents/tab_contents_view_gtk.h index 8552543..d2da996 100644 --- a/chrome/browser/tab_contents/tab_contents_view_gtk.h +++ b/chrome/browser/tab_contents/tab_contents_view_gtk.h @@ -22,7 +22,7 @@ class GtkThemeProperties; class RenderViewContextMenuGtk; class SadTabGtk; class TabContentsDragSource; -class WebDragDest; +class WebDragDestGtk; typedef struct _GtkFloatingContainer GtkFloatingContainer; class TabContentsViewGtk : public TabContentsView, @@ -133,7 +133,7 @@ class TabContentsViewGtk : public TabContentsView, // The helper object that handles drag destination related interactions with // GTK. - scoped_ptr<WebDragDest> drag_dest_; + scoped_ptr<WebDragDestGtk> drag_dest_; // Object responsible for handling drags from the page for us. scoped_ptr<TabContentsDragSource> drag_source_; diff --git a/chrome/browser/tab_contents/web_drag_dest_gtk.cc b/chrome/browser/tab_contents/web_drag_dest_gtk.cc new file mode 100644 index 0000000..6290e99 --- /dev/null +++ b/chrome/browser/tab_contents/web_drag_dest_gtk.cc @@ -0,0 +1,180 @@ +// 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/tab_contents/web_drag_dest_gtk.h" + +#include "app/gtk_dnd_util.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/gtk_util.h" + +using WebKit::WebDragOperation; +using WebKit::WebDragOperationCopy; +using WebKit::WebDragOperationNone; + +WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget) + : tab_contents_(tab_contents), + widget_(widget), + context_(NULL), + method_factory_(this) { + gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0), + NULL, 0, GDK_ACTION_COPY); + g_signal_connect(widget, "drag-motion", + G_CALLBACK(OnDragMotionThunk), this); + g_signal_connect(widget, "drag-leave", + G_CALLBACK(OnDragLeaveThunk), this); + g_signal_connect(widget, "drag-drop", + G_CALLBACK(OnDragDropThunk), this); + g_signal_connect(widget, "drag-data-received", + G_CALLBACK(OnDragDataReceivedThunk), this); + + destroy_handler_ = g_signal_connect( + widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_); +} + +WebDragDestGtk::~WebDragDestGtk() { + if (widget_) { + gtk_drag_dest_unset(widget_); + g_signal_handler_disconnect(widget_, destroy_handler_); + } +} + +void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) { + if (context_) { + // TODO(estade): we might want to support other actions besides copy, + // but that would increase the cost of getting our drag success guess + // wrong. + is_drop_target_ = operation != WebDragOperationNone; + // TODO(snej): Pass appropriate GDK action instead of hardcoding COPY + gdk_drag_status(context_, is_drop_target_ ? GDK_ACTION_COPY : + static_cast<GdkDragAction>(0), + drag_over_time_); + } +} + +void WebDragDestGtk::DragLeave() { + tab_contents_->render_view_host()->DragTargetDragLeave(); +} + +gboolean WebDragDestGtk::OnDragMotion(GdkDragContext* context, gint x, gint y, + guint time) { + if (context_ != context) { + context_ = context; + drop_data_.reset(new WebDropData); + is_drop_target_ = false; + + static int supported_targets[] = { + GtkDndUtil::TEXT_PLAIN, + GtkDndUtil::TEXT_URI_LIST, + GtkDndUtil::TEXT_HTML, + // TODO(estade): support image drags? + }; + + data_requests_ = arraysize(supported_targets); + for (size_t i = 0; i < arraysize(supported_targets); ++i) { + gtk_drag_get_data(widget_, context, + GtkDndUtil::GetAtomForTarget(supported_targets[i]), + time); + } + } else if (data_requests_ == 0) { + tab_contents_->render_view_host()-> + DragTargetDragOver(gtk_util::ClientPoint(widget_), + gtk_util::ScreenPoint(widget_), + WebDragOperationCopy); + // TODO(snej): Pass appropriate DragOperation instead of hardcoding + drag_over_time_ = time; + } + + // Pretend we are a drag destination because we don't want to wait for + // the renderer to tell us if we really are or not. + return TRUE; +} + +void WebDragDestGtk::OnDragDataReceived( + GdkDragContext* context, gint x, gint y, GtkSelectionData* data, + guint info, guint time) { + // We might get the data from an old get_data() request that we no longer + // care about. + if (context != context_) + return; + + data_requests_--; + + // Decode the data. + if (data->data) { + // If the source can't provide us with valid data for a requested target, + // data->data will be NULL. + if (data->target == + GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_PLAIN)) { + guchar* text = gtk_selection_data_get_text(data); + if (text) { + drop_data_->plain_text = + UTF8ToUTF16(std::string(reinterpret_cast<char*>(text), + data->length)); + g_free(text); + } + } else if (data->target == + GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_URI_LIST)) { + gchar** uris = gtk_selection_data_get_uris(data); + if (uris) { + for (gchar** uri_iter = uris; *uri_iter; uri_iter++) { + // TODO(estade): Can the filenames have a non-UTF8 encoding? + drop_data_->filenames.push_back(UTF8ToUTF16(*uri_iter)); + } + // Also, write the first URI as the URL. + if (uris[0]) + drop_data_->url = GURL(uris[0]); + g_strfreev(uris); + } + } else if (data->target == + GtkDndUtil::GetAtomForTarget(GtkDndUtil::TEXT_HTML)) { + // TODO(estade): Can the html have a non-UTF8 encoding? + drop_data_->text_html = + UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data), + data->length)); + // We leave the base URL empty. + } + } + + if (data_requests_ == 0) { + // Tell the renderer about the drag. + // |x| and |y| are seemingly arbitrary at this point. + tab_contents_->render_view_host()-> + DragTargetDragEnter(*drop_data_.get(), + gtk_util::ClientPoint(widget_), + gtk_util::ScreenPoint(widget_), + WebDragOperationCopy); + // TODO(snej): Pass appropriate DragOperation instead of hardcoding + drag_over_time_ = time; + } +} + +// The drag has left our widget; forward this information to the renderer. +void WebDragDestGtk::OnDragLeave(GdkDragContext* context, guint time) { + // Set |context_| to NULL to make sure we will recognize the next DragMotion + // as an enter. + context_ = NULL; + drop_data_.reset(); + // When GTK sends us a drag-drop signal, it is shortly (and synchronously) + // preceded by a drag-leave. The renderer doesn't like getting the signals + // in this order so delay telling it about the drag-leave till we are sure + // we are not getting a drop as well. + MessageLoop::current()->PostTask(FROM_HERE, + method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave)); +} + +// Called by GTK when the user releases the mouse, executing a drop. +gboolean WebDragDestGtk::OnDragDrop(GdkDragContext* context, gint x, gint y, + guint time) { + // Cancel that drag leave! + method_factory_.RevokeAll(); + + tab_contents_->render_view_host()-> + 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. + gtk_drag_finish(context, is_drop_target_, FALSE, time); + return TRUE; +} diff --git a/chrome/browser/tab_contents/web_drag_dest_gtk.h b/chrome/browser/tab_contents/web_drag_dest_gtk.h new file mode 100644 index 0000000..8bba71e --- /dev/null +++ b/chrome/browser/tab_contents/web_drag_dest_gtk.h @@ -0,0 +1,105 @@ +// 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_TAB_CONTENTS_WEB_DRAG_DEST_GTK_H_ +#define CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_DEST_GTK_H_ + +#include <gtk/gtk.h> + +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "webkit/api/public/WebDragOperation.h" +#include "webkit/glue/webdropdata.h" + +class TabContents; + +// A helper class that handles DnD for drops in the renderer. In GTK parlance, +// this handles destination-side DnD, but not source-side DnD. +class WebDragDestGtk { + public: + WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget); + ~WebDragDestGtk(); + + // This is called when the renderer responds to a drag motion event. We must + // update the system drag cursor. + void UpdateDragStatus(WebKit::WebDragOperation operation); + + // Informs the renderer when a system drag has left the render view. + // See OnDragLeave(). + void DragLeave(); + + private: + static gboolean OnDragMotionThunk( + GtkWidget* widget, GdkDragContext* drag_context, gint x, gint y, + guint time, WebDragDestGtk* dest) { + return dest->OnDragMotion(drag_context, x, y, time); + } + static void OnDragLeaveThunk( + GtkWidget* widget, GdkDragContext* drag_context, guint time, + WebDragDestGtk* dest) { + dest->OnDragLeave(drag_context, time); + } + static gboolean OnDragDropThunk( + GtkWidget* widget, GdkDragContext* drag_context, gint x, gint y, + guint time, WebDragDestGtk* dest) { + return dest->OnDragDrop(drag_context, x, y, time); + } + static void OnDragDataReceivedThunk( + GtkWidget* widget, GdkDragContext* drag_context, gint x, gint y, + GtkSelectionData* data, guint info, guint time, WebDragDestGtk* dest) { + dest->OnDragDataReceived(drag_context, x, y, data, info, time); + } + + // Called when a system drag crosses over the render view. As there is no drag + // enter event, we treat it as an enter event (and not a regular motion event) + // when |context_| is NULL. + gboolean OnDragMotion(GdkDragContext* context, gint x, gint y, guint time); + + // We make a series of requests for the drag data when the drag first enters + // the render view. This is the callback that is used to give us the data + // for each individual target. When |data_requests_| reaches 0, we know we + // have attained all the data, and we can finally tell the renderer about the + // drag. + void OnDragDataReceived(GdkDragContext* context, gint x, gint y, + GtkSelectionData* data, guint info, guint time); + + // The drag has left our widget; forward this information to the renderer. + void OnDragLeave(GdkDragContext* context, guint time); + + // Called by GTK when the user releases the mouse, executing a drop. + gboolean OnDragDrop(GdkDragContext* context, gint x, gint y, guint time); + + + TabContents* tab_contents_; + // The render view. + GtkWidget* widget_; + // The current drag context for system drags over our render view, or NULL if + // there is no system drag or the system drag is not over our render view. + GdkDragContext* context_; + // The data for the current drag, or NULL if |context_| is NULL. + scoped_ptr<WebDropData> drop_data_; + + // The number of outstanding drag data requests we have sent to the drag + // source. + int data_requests_; + + // The last time we sent a message to the renderer related to a drag motion. + gint drag_over_time_; + + // Whether the cursor is over a drop target, according to the last message we + // got from the renderer. + bool is_drop_target_; + + // Handler ID for the destroy signal handler. We connect to the destroy + // signal handler so that we won't call dest_unset on it after it is + // destroyed, but we have to cancel the handler if we are destroyed before + // |widget_| is. + int destroy_handler_; + + ScopedRunnableMethodFactory<WebDragDestGtk> method_factory_; + + DISALLOW_COPY_AND_ASSIGN(WebDragDestGtk); +}; + +#endif // CHROME_BROWSER_TAB_CONTENTS_WEB_DRAG_DEST_GTK_H_ |