diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-28 00:45:35 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-28 00:45:35 +0000 |
commit | 903e7a8a5f8948b96c46f16c4920648c29a5af12 (patch) | |
tree | d34d420a39ce4e3e8048ec5503d9c255617ca357 /chrome/browser | |
parent | f05798163ceb52a2694e59c1a7f40ace72fb2024 (diff) | |
download | chromium_src-903e7a8a5f8948b96c46f16c4920648c29a5af12.zip chromium_src-903e7a8a5f8948b96c46f16c4920648c29a5af12.tar.gz chromium_src-903e7a8a5f8948b96c46f16c4920648c29a5af12.tar.bz2 |
Gtk: DnD extravaganza
- Correctly update drag status for drags over renderer. This makes things look quite a bit better.
- Rework the dnd utils so that we specify the drag targets in the order we prefer them (for destinations)
- Refactor code in bookmark bar so folder and toolbar drags share more code
- Allow bookmark bar to accept URI lists and plain text drags (for plain text we require the text to be a valid url)
BUG=17431
Review URL: http://codereview.chromium.org/159419
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21767 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/bookmarks/bookmark_utils.cc | 10 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_utils.h | 5 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bar_gtk.cc | 132 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bar_gtk.h | 26 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_manager_gtk.cc | 12 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_utils_gtk.cc | 29 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_utils_gtk.h | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.cc | 6 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_dnd_util.cc | 73 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_dnd_util.h | 11 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.cc | 4 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_view_gtk.cc | 23 |
12 files changed, 196 insertions, 143 deletions
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc index f08560a..83d0bb3 100644 --- a/chrome/browser/bookmarks/bookmark_utils.cc +++ b/chrome/browser/bookmarks/bookmark_utils.cc @@ -28,6 +28,7 @@ #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" +#include "grit/app_strings.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "net/base/net_util.h" @@ -417,6 +418,15 @@ bool CanPasteFromClipboard(const BookmarkNode* node) { #endif } +std::string GetNameForURL(const GURL& url) { + if (url.is_valid()) { + return WideToUTF8(net::GetSuggestedFilename( + url, std::string(), std::string(), std::wstring())); + } else { + return l10n_util::GetStringUTF8(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME); + } +} + std::vector<const BookmarkNode*> GetMostRecentlyModifiedGroups( BookmarkModel* model, size_t max_count) { diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h index 97eec88..0c4ecab 100644 --- a/chrome/browser/bookmarks/bookmark_utils.h +++ b/chrome/browser/bookmarks/bookmark_utils.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_ #define CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_ +#include <string> #include <vector> #include "base/gfx/native_widget_types.h" @@ -103,6 +104,10 @@ void PasteFromClipboard(BookmarkModel* model, // Returns true if the user can copy from the pasteboard. bool CanPasteFromClipboard(const BookmarkNode* node); +// Returns a name for the given URL. Used for drags into bookmark areas when +// the source doesn't specify a title. +std::string GetNameForURL(const GURL& url); + // Returns a vector containing up to |max_count| of the most recently modified // groups. This never returns an empty vector. std::vector<const BookmarkNode*> GetMostRecentlyModifiedGroups( diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc index 877d2af..5e2c736 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.cc +++ b/chrome/browser/gtk/bookmark_bar_gtk.cc @@ -48,6 +48,12 @@ const int kInstructionsPadding = 6; // Color of the instructional text. const GdkColor kInstructionsColor = GDK_COLOR_RGB(128, 128, 142); +// The targets accepted by the toolbar and folder buttons for DnD. +const int kDestTargetList[] = { GtkDndUtil::CHROME_BOOKMARK_ITEM, + GtkDndUtil::CHROME_NAMED_URL, + GtkDndUtil::TEXT_URI_LIST, + GtkDndUtil::TEXT_PLAIN, -1 }; + void SetToolBarStyle() { static bool style_was_set = false; @@ -159,15 +165,13 @@ void BookmarkBarGtk::Init(Profile* profile) { gtk_drag_dest_set(bookmark_toolbar_.get(), GTK_DEST_DEFAULT_DROP, NULL, 0, GDK_ACTION_MOVE); - GtkDndUtil::SetDestTargetListFromCodeMask(bookmark_toolbar_.get(), - GtkDndUtil::CHROME_BOOKMARK_ITEM | - GtkDndUtil::CHROME_NAMED_URL); + GtkDndUtil::SetDestTargetList(bookmark_toolbar_.get(), kDestTargetList); g_signal_connect(bookmark_toolbar_.get(), "drag-motion", G_CALLBACK(&OnToolbarDragMotion), this); g_signal_connect(bookmark_toolbar_.get(), "drag-leave", G_CALLBACK(&OnToolbarDragLeave), this); g_signal_connect(bookmark_toolbar_.get(), "drag-data-received", - G_CALLBACK(&OnToolbarDragReceived), this); + G_CALLBACK(&OnDragReceived), this); g_signal_connect(bookmark_toolbar_.get(), "button-press-event", G_CALLBACK(&OnButtonPressed), this); @@ -449,11 +453,9 @@ GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(const BookmarkNode* node) { void BookmarkBarGtk::ConnectFolderButtonEvents(GtkWidget* widget) { gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_MOVE); - GtkDndUtil::SetDestTargetListFromCodeMask(widget, - GtkDndUtil::CHROME_BOOKMARK_ITEM | - GtkDndUtil::CHROME_NAMED_URL); + GtkDndUtil::SetDestTargetList(widget, kDestTargetList); g_signal_connect(widget, "drag-data-received", - G_CALLBACK(&OnFolderDragReceived), this); + G_CALLBACK(&OnDragReceived), this); // Connect to 'button-release-event' instead of 'clicked' because we need // access to the modifier keys and we do different things on each @@ -666,40 +668,6 @@ gboolean BookmarkBarGtk::OnFolderButtonReleased(GtkWidget* sender, } // static -void BookmarkBarGtk::OnFolderDragReceived(GtkWidget* widget, - GdkDragContext* context, gint x, gint y, GtkSelectionData* selection_data, - guint target_type, guint time, BookmarkBarGtk* bar) { - gboolean dnd_success = FALSE; - gboolean delete_selection_data = FALSE; - - const BookmarkNode* dest_node = bar->GetNodeForToolButton(widget); - DCHECK(dest_node->is_folder()); - - if (target_type == GtkDndUtil::CHROME_BOOKMARK_ITEM) { - std::vector<const BookmarkNode*> nodes = - bookmark_utils::GetNodesFromSelection(context, selection_data, - target_type, - bar->profile_, - &delete_selection_data, - &dnd_success); - DCHECK(!nodes.empty()); - DCHECK(dnd_success); - - for (std::vector<const BookmarkNode*>::iterator it = nodes.begin(); - it != nodes.end(); ++it) { - bar->model_->Move(*it, dest_node, dest_node->GetChildCount()); - } - } else if (target_type == GtkDndUtil::CHROME_NAMED_URL) { - dnd_success = bookmark_utils::CreateNewBookmarkFromNamedUrl( - selection_data, bar->model_, dest_node, dest_node->GetChildCount()); - } else { - NOTREACHED(); - } - - gtk_drag_finish(context, dnd_success, delete_selection_data, time); -} - -// static gboolean BookmarkBarGtk::OnToolbarExpose(GtkWidget* widget, GdkEventExpose* event, BookmarkBarGtk* bar) { @@ -771,36 +739,68 @@ void BookmarkBarGtk::OnToolbarDragLeave(GtkToolbar* toolbar, } // static -void BookmarkBarGtk::OnToolbarDragReceived(GtkWidget* widget, - GdkDragContext* context, - gint x, gint y, - GtkSelectionData* selection_data, - guint target_type, guint time, - BookmarkBarGtk* bar) { +void BookmarkBarGtk::OnDragReceived(GtkWidget* widget, + GdkDragContext* context, + gint x, gint y, + GtkSelectionData* selection_data, + guint target_type, guint time, + BookmarkBarGtk* bar) { gboolean dnd_success = FALSE; gboolean delete_selection_data = FALSE; - gint index = gtk_toolbar_get_drop_index( + const BookmarkNode* dest_node; + gint index; + if (widget == bar->bookmark_toolbar_.get()) { + dest_node = bar->model_->GetBookmarkBarNode(); + index = gtk_toolbar_get_drop_index( GTK_TOOLBAR(bar->bookmark_toolbar_.get()), x, y); + } else { + dest_node = bar->GetNodeForToolButton(widget); + index = dest_node->GetChildCount(); + } - if (target_type == GtkDndUtil::CHROME_BOOKMARK_ITEM) { - std::vector<const BookmarkNode*> nodes = - bookmark_utils::GetNodesFromSelection(context, selection_data, - target_type, - bar->profile_, - &delete_selection_data, - &dnd_success); - DCHECK(!nodes.empty()); - for (std::vector<const BookmarkNode*>::iterator it = nodes.begin(); - it != nodes.end(); ++it) { - bar->model_->Move(*it, bar->model_->GetBookmarkBarNode(), index); - index = bar->model_->GetBookmarkBarNode()->IndexOfChild(*it) + 1; + switch (target_type) { + case GtkDndUtil::CHROME_BOOKMARK_ITEM: { + std::vector<const BookmarkNode*> nodes = + bookmark_utils::GetNodesFromSelection(context, selection_data, + target_type, + bar->profile_, + &delete_selection_data, + &dnd_success); + DCHECK(!nodes.empty()); + for (std::vector<const BookmarkNode*>::iterator it = nodes.begin(); + it != nodes.end(); ++it) { + bar->model_->Move(*it, dest_node, index); + index = dest_node->IndexOfChild(*it) + 1; + } + break; + } + + case GtkDndUtil::CHROME_NAMED_URL: { + dnd_success = bookmark_utils::CreateNewBookmarkFromNamedUrl( + selection_data, bar->model_, dest_node, index); + break; + } + + case GtkDndUtil::TEXT_URI_LIST: { + dnd_success = bookmark_utils::CreateNewBookmarksFromURIList( + selection_data, bar->model_, dest_node, index); + break; + } + + case GtkDndUtil::TEXT_PLAIN: { + guchar* text = gtk_selection_data_get_text(selection_data); + GURL url(reinterpret_cast<char*>(text)); + g_free(text); + // TODO(estade): It would be nice to head this case off at drag motion, + // so that it doesn't look like we can drag onto the bookmark bar. + if (!url.is_valid()) + break; + std::string title = bookmark_utils::GetNameForURL(url); + bar->model_->AddURL(dest_node, index, UTF8ToWide(title), url); + dnd_success = TRUE; + break; } - } else if (target_type == GtkDndUtil::CHROME_NAMED_URL) { - dnd_success = bookmark_utils::CreateNewBookmarkFromNamedUrl( - selection_data, bar->model_, bar->model_->GetBookmarkBarNode(), index); - } else { - NOTREACHED(); } gtk_drag_finish(context, dnd_success, delete_selection_data, time); diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h index faac53a..5220b95 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.h +++ b/chrome/browser/gtk/bookmark_bar_gtk.h @@ -142,7 +142,7 @@ class BookmarkBarGtk : public AnimationDelegate, void PopupMenuForNode(GtkWidget* sender, const BookmarkNode* node, GdkEventButton* event); - // GtkButton callbacks + // GtkButton callbacks. static gboolean OnButtonPressed(GtkWidget* sender, GdkEventButton* event, BookmarkBarGtk* bar); @@ -160,18 +160,12 @@ class BookmarkBarGtk : public AnimationDelegate, guint target_type, guint time, BookmarkBarGtk* bar); - // GtkButton callbacks for folder buttons + // GtkButton callbacks for folder buttons. static gboolean OnFolderButtonReleased(GtkWidget* sender, GdkEventButton* event, BookmarkBarGtk* bar); - static void OnFolderDragReceived(GtkWidget* widget, - GdkDragContext* context, - gint x, gint y, - GtkSelectionData* selection_data, - guint target_type, guint time, - BookmarkBarGtk* bar); - // GtkToolbar callbacks + // GtkToolbar callbacks. static gboolean OnToolbarExpose(GtkWidget* widget, GdkEventExpose* event, BookmarkBarGtk* window); static gboolean OnToolbarDragMotion(GtkToolbar* toolbar, @@ -184,12 +178,14 @@ class BookmarkBarGtk : public AnimationDelegate, GdkDragContext* context, guint time, BookmarkBarGtk* bar); - static void OnToolbarDragReceived(GtkWidget* widget, - GdkDragContext* context, - gint x, gint y, - GtkSelectionData* selection_data, - guint target_type, guint time, - BookmarkBarGtk* bar); + + // Used for both folder buttons and the toolbar. + static void OnDragReceived(GtkWidget* widget, + GdkDragContext* context, + gint x, gint y, + GtkSelectionData* selection_data, + guint target_type, guint time, + BookmarkBarGtk* bar); // GtkHBox callbacks. static gboolean OnHBoxExpose(GtkWidget* widget, GdkEventExpose* event, diff --git a/chrome/browser/gtk/bookmark_manager_gtk.cc b/chrome/browser/gtk/bookmark_manager_gtk.cc index 25ae32f..ef58e88 100644 --- a/chrome/browser/gtk/bookmark_manager_gtk.cc +++ b/chrome/browser/gtk/bookmark_manager_gtk.cc @@ -54,6 +54,9 @@ const int kSearchDelayMS = 200; // resizes the column. const int kDefaultColumnWidth = 200; +// The targets that the right tree view accepts for dragging. +const int kDestTargetList[] = { GtkDndUtil::CHROME_BOOKMARK_ITEM, -1 }; + // We only have one manager open at a time. BookmarkManagerGtk* manager = NULL; @@ -449,8 +452,7 @@ GtkWidget* BookmarkManagerGtk::MakeLeftPane() { // The left side is only a drag destination (not a source). gtk_drag_dest_set(left_tree_view_, GTK_DEST_DEFAULT_DROP, NULL, 0, GDK_ACTION_MOVE); - GtkDndUtil::SetDestTargetListFromCodeMask(left_tree_view_, - GtkDndUtil::CHROME_BOOKMARK_ITEM); + GtkDndUtil::SetDestTargetList(left_tree_view_, kDestTargetList); g_signal_connect(left_tree_view_, "drag-data-received", G_CALLBACK(&OnLeftTreeViewDragReceived), this); @@ -525,8 +527,7 @@ GtkWidget* BookmarkManagerGtk::MakeRightPane() { GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_MOVE); GtkDndUtil::SetSourceTargetListFromCodeMask( - right_tree_view_, GtkDndUtil::CHROME_BOOKMARK_ITEM | - GtkDndUtil::TEXT_URI_LIST); + right_tree_view_, GtkDndUtil::CHROME_BOOKMARK_ITEM); // We connect to drag dest signals, but we don't actually enable the widget // as a drag destination unless it corresponds to the contents of a folder. @@ -618,8 +619,7 @@ void BookmarkManagerGtk::BuildRightStore() { gtk_drag_dest_set(right_tree_view_, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_MOVE); - GtkDndUtil::SetDestTargetListFromCodeMask(right_tree_view_, - GtkDndUtil::CHROME_BOOKMARK_ITEM); + GtkDndUtil::SetDestTargetList(right_tree_view_, kDestTargetList); } else { SaveColumnConfiguration(); gtk_tree_view_column_set_visible(path_column_, TRUE); diff --git a/chrome/browser/gtk/bookmark_utils_gtk.cc b/chrome/browser/gtk/bookmark_utils_gtk.cc index fa2a56e..07e87ec 100644 --- a/chrome/browser/gtk/bookmark_utils_gtk.cc +++ b/chrome/browser/gtk/bookmark_utils_gtk.cc @@ -10,6 +10,7 @@ #include "base/string_util.h" #include "chrome/browser/bookmarks/bookmark_drag_data.h" #include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/gtk/gtk_chrome_button.h" #include "chrome/browser/gtk/gtk_dnd_util.h" #include "chrome/browser/gtk/gtk_theme_provider.h" @@ -209,7 +210,7 @@ void WriteBookmarksToSelection(const std::vector<const BookmarkNode*>& nodes, for (size_t i = 0; i < nodes.size(); ++i) { // If the node is a folder, this will be empty. TODO(estade): figure out // if there are any ramifications to passing an empty URI. After a - // lttle testing, it seems fine. + // little testing, it seems fine. const GURL& url = nodes[i]->GetURL(); // This const cast should be safe as gtk_selection_data_set_uris() // makes copies. @@ -268,9 +269,31 @@ bool CreateNewBookmarkFromNamedUrl(GtkSelectionData* selection_data, std::string title_utf8, url_utf8; bool rv = data.ReadString(&iter, &title_utf8); rv = rv && data.ReadString(&iter, &url_utf8); - if (rv) - model->AddURL(parent, idx, UTF8ToWide(title_utf8), GURL(url_utf8)); + if (rv) { + GURL url(url_utf8); + if (title_utf8.empty()) + title_utf8 = GetNameForURL(url); + model->AddURL(parent, idx, UTF8ToWide(title_utf8), url); + } return rv; } +bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data, + BookmarkModel* model, const BookmarkNode* parent, int idx) { + gchar** uris = gtk_selection_data_get_uris(selection_data); + if (!uris) { + NOTREACHED(); + return false; + } + + for (size_t i = 0; uris[i] != NULL; ++i) { + GURL url(uris[i]); + std::string title = GetNameForURL(url); + model->AddURL(parent, idx++, UTF8ToWide(title), url); + } + + g_strfreev(uris); + return true; +} + } // namespace bookmark_utils diff --git a/chrome/browser/gtk/bookmark_utils_gtk.h b/chrome/browser/gtk/bookmark_utils_gtk.h index d2d0143..865a79e 100644 --- a/chrome/browser/gtk/bookmark_utils_gtk.h +++ b/chrome/browser/gtk/bookmark_utils_gtk.h @@ -83,6 +83,14 @@ bool CreateNewBookmarkFromNamedUrl( const BookmarkNode* parent, int idx); +// Add the URIs in |selection_data| into the model at the given position. They +// will be added whether or not the URL is valid. +bool CreateNewBookmarksFromURIList( + GtkSelectionData* selection_data, + BookmarkModel* model, + const BookmarkNode* parent, + int idx); + } // namespace bookmark_utils #endif // CHROME_BROWSER_GTK_BOOKMARK_UTILS_GTK_H_ diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc index 06200a6..dfaad68 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_gtk.cc @@ -452,9 +452,9 @@ void BrowserToolbarGtk::SetUpDragForHomeButton() { // prefer URIs over plain text when both are available. gtk_drag_dest_set(home_->widget(), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY); - GtkDndUtil::SetDestTargetListFromCodeMask(home_->widget(), - GtkDndUtil::TEXT_PLAIN | - GtkDndUtil::TEXT_URI_LIST); + static const int targets[] = { GtkDndUtil::TEXT_PLAIN, + GtkDndUtil::TEXT_URI_LIST, -1 }; + GtkDndUtil::SetDestTargetList(home_->widget(), targets); g_signal_connect(home_->widget(), "drag-data-received", G_CALLBACK(OnDragDataReceived), this); diff --git a/chrome/browser/gtk/gtk_dnd_util.cc b/chrome/browser/gtk/gtk_dnd_util.cc index ebc2412..92a5602 100644 --- a/chrome/browser/gtk/gtk_dnd_util.cc +++ b/chrome/browser/gtk/gtk_dnd_util.cc @@ -6,17 +6,6 @@ #include "base/logging.h" -namespace { - -void AddApplicationTarget(GtkTargetList* targets, int code_mask, int target) { - if (code_mask & target) { - gtk_target_list_add(targets, GtkDndUtil::GetAtomForTarget(target), - GTK_TARGET_SAME_APP, target); - } -} - -} // namespace - // static GdkAtom GtkDndUtil::GetAtomForTarget(int target) { switch (target) { @@ -61,34 +50,60 @@ GdkAtom GtkDndUtil::GetAtomForTarget(int target) { GtkTargetList* GtkDndUtil::GetTargetListFromCodeMask(int code_mask) { GtkTargetList* targets = gtk_target_list_new(NULL, 0); - if (code_mask & TEXT_PLAIN) - gtk_target_list_add_text_targets(targets, TEXT_PLAIN); + for (size_t i = 1; i < INVALID_TARGET; i = i << 1) { + if (i == CHROME_WEBDROP_FILE_CONTENTS) + continue; - if (code_mask & TEXT_URI_LIST) - gtk_target_list_add_uri_targets(targets, TEXT_URI_LIST); - - if (code_mask & TEXT_HTML) - gtk_target_list_add(targets, GetAtomForTarget(TEXT_PLAIN), 0, TEXT_HTML); - - AddApplicationTarget(targets, code_mask, CHROME_TAB); - AddApplicationTarget(targets, code_mask, CHROME_BOOKMARK_ITEM); - AddApplicationTarget(targets, code_mask, CHROME_NAMED_URL); + if (i & code_mask) + AddTargetToList(targets, i); + } return targets; } // static -void GtkDndUtil::SetDestTargetListFromCodeMask(GtkWidget* dest, - int code_mask) { +void GtkDndUtil::SetSourceTargetListFromCodeMask(GtkWidget* source, + int code_mask) { GtkTargetList* targets = GetTargetListFromCodeMask(code_mask); - gtk_drag_dest_set_target_list(dest, targets); + gtk_drag_source_set_target_list(source, targets); gtk_target_list_unref(targets); } // static -void GtkDndUtil::SetSourceTargetListFromCodeMask(GtkWidget* source, - int code_mask) { - GtkTargetList* targets = GetTargetListFromCodeMask(code_mask); - gtk_drag_source_set_target_list(source, targets); +void GtkDndUtil::SetDestTargetList(GtkWidget* dest, const int* target_codes) { + GtkTargetList* targets = gtk_target_list_new(NULL, 0); + + for (size_t i = 0; target_codes[i] != -1; ++i) { + AddTargetToList(targets, target_codes[i]); + } + + gtk_drag_dest_set_target_list(dest, targets); gtk_target_list_unref(targets); } + +// static +void GtkDndUtil::AddTargetToList(GtkTargetList* targets, int target_code) { + switch (target_code) { + case TEXT_PLAIN: + gtk_target_list_add_text_targets(targets, TEXT_PLAIN); + break; + + case TEXT_URI_LIST: + gtk_target_list_add_uri_targets(targets, TEXT_URI_LIST); + break; + + case TEXT_HTML: + gtk_target_list_add(targets, GetAtomForTarget(TEXT_PLAIN), 0, TEXT_HTML); + break; + + case CHROME_TAB: + case CHROME_BOOKMARK_ITEM: + case CHROME_NAMED_URL: + gtk_target_list_add(targets, GtkDndUtil::GetAtomForTarget(target_code), + GTK_TARGET_SAME_APP, target_code); + break; + + default: + NOTREACHED() << " Unexpected target code: " << target_code; + } +} diff --git a/chrome/browser/gtk/gtk_dnd_util.h b/chrome/browser/gtk/gtk_dnd_util.h index 42432c7..2ac5433 100644 --- a/chrome/browser/gtk/gtk_dnd_util.h +++ b/chrome/browser/gtk/gtk_dnd_util.h @@ -21,6 +21,8 @@ class GtkDndUtil { TEXT_PLAIN = 1 << 4, TEXT_URI_LIST = 1 << 5, TEXT_HTML = 1 << 6, + + INVALID_TARGET = 1 << 7, }; // Get the atom for a given target (of the above enum type). Will return NULL @@ -35,13 +37,18 @@ class GtkDndUtil { // of the client code to do the right thing. static GtkTargetList* GetTargetListFromCodeMask(int code_mask); - // Set the drag target list for |dest| or |source| with the target list that + // Set the drag target list for |source| with the target list that // corresponds to |code_mask|. - static void SetDestTargetListFromCodeMask(GtkWidget* dest, int code_mask); static void SetSourceTargetListFromCodeMask(GtkWidget* source, int code_mask); + // Set the accepted targets list for |dest|. The |target_codes| array should + // be sorted in preference order and should be terminated with -1. + static void SetDestTargetList(GtkWidget* dest, const int* target_codes); + private: GtkDndUtil(); + + static void AddTargetToList(GtkTargetList* targets, int target_code); }; #endif // CHROME_BROWSER_GTK_GTK_DND_UTIL_H_ diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index 27a1d02..3af798a 100644 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -701,8 +701,8 @@ void TabStripGtk::Init() { NULL, 0, static_cast<GdkDragAction>( GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK)); - GtkDndUtil::SetDestTargetListFromCodeMask(tabstrip_.get(), - GtkDndUtil::TEXT_URI_LIST); + static const int targets[] = { GtkDndUtil::TEXT_URI_LIST, -1 }; + GtkDndUtil::SetDestTargetList(tabstrip_.get(), targets); g_signal_connect(G_OBJECT(tabstrip_.get()), "expose-event", G_CALLBACK(OnExpose), this); diff --git a/chrome/browser/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/tab_contents/tab_contents_view_gtk.cc index 5368233..7adc0a2 100644 --- a/chrome/browser/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/tab_contents/tab_contents_view_gtk.cc @@ -8,11 +8,11 @@ #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> -#include "app/l10n_util.h" #include "base/mime_util.h" #include "base/gfx/point.h" #include "base/gfx/rect.h" #include "base/gfx/size.h" +#include "base/pickle.h" #include "base/string_util.h" #include "build/build_config.h" #include "chrome/browser/download/download_shelf.h" @@ -34,8 +34,6 @@ #include "chrome/common/notification_service.h" #include "chrome/common/notification_source.h" #include "chrome/common/notification_type.h" -#include "grit/app_strings.h" -#include "net/base/net_util.h" #include "webkit/glue/webdropdata.h" namespace { @@ -231,7 +229,9 @@ class WebDragDest { // TODO(estade): we might want to support other actions besides copy, // but that would increase the cost of getting our drag success guess // wrong. - gdk_drag_status(context_, GDK_ACTION_COPY, drag_over_time_); + gdk_drag_status(context_, is_drop_target ? GDK_ACTION_COPY : + static_cast<GdkDragAction>(0), + drag_over_time_); is_drop_target_ = false; } } @@ -820,20 +820,9 @@ void TabContentsViewGtk::OnDragDataGet( } case GtkDndUtil::CHROME_NAMED_URL: { - std::string name; - const GURL& url = view->drop_data_->url; - if (!view->drop_data_->url_title.empty()) { - name = UTF16ToUTF8(view->drop_data_->url_title); - } else if (url.is_valid()) { - name = WideToUTF8(net::GetSuggestedFilename( - url, std::string(), std::string(), std::wstring())); - } else { - // Nothing else can be done, just use a default. - name = l10n_util::GetStringUTF8(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME); - } Pickle pickle; - pickle.WriteString(name); - pickle.WriteString(url.spec()); + pickle.WriteString(UTF16ToUTF8(view->drop_data_->url_title)); + pickle.WriteString(view->drop_data_->url.spec()); gtk_selection_data_set(selection_data, GtkDndUtil::GetAtomForTarget(GtkDndUtil::CHROME_NAMED_URL), bits_per_byte, |