summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-15 22:33:13 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-15 22:33:13 +0000
commitd90eaa38f5cd59970b50491b7e5bda8b230614b7 (patch)
tree747e5d4af61d9a97014036f7025df1b7fe5cdf6d
parent7f8bd32d382cc3f1cd70670d40f5f96d69e5d6ea (diff)
downloadchromium_src-d90eaa38f5cd59970b50491b7e5bda8b230614b7.zip
chromium_src-d90eaa38f5cd59970b50491b7e5bda8b230614b7.tar.gz
chromium_src-d90eaa38f5cd59970b50491b7e5bda8b230614b7.tar.bz2
GTK: Modify the bookmark bar to actually use GTK drag and drop.
(Previously, DnD support was faked and would crash the application in a variety of not-really corner cases.) http://crbug.com/10964 Review URL: http://codereview.chromium.org/115388 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16203 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.cc83
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.h20
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc145
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.h17
4 files changed, 202 insertions, 63 deletions
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.cc b/chrome/browser/bookmarks/bookmark_drag_data.cc
index c5a56ed..fcfcae4 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.cc
+++ b/chrome/browser/bookmarks/bookmark_drag_data.cc
@@ -19,16 +19,14 @@
#if defined(OS_WIN)
static CLIPFORMAT clipboard_format = 0;
-#endif
static void RegisterFormat() {
-#if defined(OS_WIN)
if (clipboard_format == 0) {
clipboard_format = RegisterClipboardFormat(L"chrome/x-bookmark-entries");
DCHECK(clipboard_format);
}
-#endif
}
+#endif
BookmarkDragData::Element::Element(BookmarkNode* node)
: is_url(node->is_url()),
@@ -87,6 +85,7 @@ BookmarkDragData::BookmarkDragData(const std::vector<BookmarkNode*>& nodes) {
elements.push_back(Element(nodes[i]));
}
+#if defined(OS_WIN)
void BookmarkDragData::Write(Profile* profile, OSExchangeData* data) const {
RegisterFormat();
@@ -103,19 +102,9 @@ void BookmarkDragData::Write(Profile* profile, OSExchangeData* data) const {
}
Pickle data_pickle;
- data_pickle.WriteWString(
- profile ? profile->GetPath().ToWStringHack() : std::wstring());
- data_pickle.WriteSize(elements.size());
-
- for (size_t i = 0; i < elements.size(); ++i)
- elements[i].WriteToPickle(&data_pickle);
+ WriteToPickle(profile, &data_pickle);
-#if defined(OS_WIN)
data->SetPickledData(clipboard_format, data_pickle);
-#else
- // TODO(port): Clipboard integration.
- NOTIMPLEMENTED();
-#endif
}
bool BookmarkDragData::Read(const OSExchangeData& data) {
@@ -125,24 +114,11 @@ bool BookmarkDragData::Read(const OSExchangeData& data) {
profile_path_.clear();
-#if defined(OS_WIN)
if (data.HasFormat(clipboard_format)) {
Pickle drag_data_pickle;
if (data.GetPickledData(clipboard_format, &drag_data_pickle)) {
- void* data_iterator = NULL;
- size_t element_count;
- if (drag_data_pickle.ReadWString(&data_iterator, &profile_path_) &&
- drag_data_pickle.ReadSize(&data_iterator, &element_count)) {
- std::vector<Element> tmp_elements;
- tmp_elements.resize(element_count);
- for (size_t i = 0; i < element_count; ++i) {
- if (!tmp_elements[i].ReadFromPickle(&drag_data_pickle,
- &data_iterator)) {
- return false;
- }
- }
- elements.swap(tmp_elements);
- }
+ if (!ReadFromPickle(&drag_data_pickle))
+ return false;
}
} else {
// See if there is a URL on the clipboard.
@@ -153,12 +129,51 @@ bool BookmarkDragData::Read(const OSExchangeData& data) {
elements.push_back(element);
}
}
+
+ return is_valid();
+}
+#endif
+
+void BookmarkDragData::WriteToPickle(Profile* profile, Pickle* pickle) const {
+#if defined(WCHAR_T_IS_UTF16)
+ pickle->WriteWString(
+ profile ? profile->GetPath().ToWStringHack() : std::wstring());
+#elif defined(WCHAR_T_IS_UTF32)
+ pickle->WriteString(
+ profile ? profile->GetPath().value() : std::string());
#else
- // TODO(port): Clipboard integration.
- NOTIMPLEMENTED();
+ NOTIMPLEMENTED() << "Impossible encoding situation!";
#endif
- return is_valid();
+ pickle->WriteSize(elements.size());
+
+ for (size_t i = 0; i < elements.size(); ++i)
+ elements[i].WriteToPickle(pickle);
+}
+
+bool BookmarkDragData::ReadFromPickle(Pickle* pickle) {
+ void* data_iterator = NULL;
+ size_t element_count;
+#if defined(WCHAR_T_IS_UTF16)
+ if (pickle->ReadWString(&data_iterator, &profile_path_) &&
+#elif defined(WCHAR_T_IS_UTF32)
+ if (pickle->ReadString(&data_iterator, &profile_path_) &&
+#else
+ NOTIMPLEMENTED() << "Impossible encoding situation!";
+ if (false &&
+#endif
+ pickle->ReadSize(&data_iterator, &element_count)) {
+ std::vector<Element> tmp_elements;
+ tmp_elements.resize(element_count);
+ for (size_t i = 0; i < element_count; ++i) {
+ if (!tmp_elements[i].ReadFromPickle(pickle, &data_iterator)) {
+ return false;
+ }
+ }
+ elements.swap(tmp_elements);
+ }
+
+ return true;
}
std::vector<BookmarkNode*> BookmarkDragData::GetNodes(Profile* profile) const {
@@ -187,5 +202,9 @@ BookmarkNode* BookmarkDragData::GetFirstNode(Profile* profile) const {
bool BookmarkDragData::IsFromProfile(Profile* profile) const {
// An empty path means the data is not associated with any profile.
return (!profile_path_.empty() &&
+#if defined(WCHAR_T_IS_UTF16)
profile->GetPath().ToWStringHack() == profile_path_);
+#elif defined(WCHAR_T_IS_UTF32)
+ profile->GetPath().value() == profile_path_);
+#endif
}
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.h b/chrome/browser/bookmarks/bookmark_drag_data.h
index b02be0c..18353e6 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.h
+++ b/chrome/browser/bookmarks/bookmark_drag_data.h
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_
-#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_
+#ifndef CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_H_
+#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_H_
+#include <string>
#include <vector>
#include "chrome/browser/history/history.h"
@@ -35,7 +36,6 @@ class Profile;
// // data is valid, contents are in elements.
struct BookmarkDragData {
-
// Element represents a single node.
struct Element {
explicit Element(BookmarkNode* node);
@@ -71,6 +71,7 @@ struct BookmarkDragData {
explicit BookmarkDragData(BookmarkNode* node);
explicit BookmarkDragData(const std::vector<BookmarkNode*>& nodes);
+#if defined(OS_WIN)
// Writes elements to data. If there is only one element and it is a URL
// the URL and title are written to the clipboard in a format other apps can
// use.
@@ -80,6 +81,13 @@ struct BookmarkDragData {
// Restores this data from the clipboard, returning true on success.
bool Read(const OSExchangeData& data);
+#endif
+
+ // Writes the data for a drag to |pickle|.
+ void WriteToPickle(Profile* profile, Pickle* pickle) const;
+
+ // Reads the data for a drag from a |pickle|.
+ bool ReadFromPickle(Pickle* pickle);
// Returns the nodes represented by this DragData. If this DragData was
// created from the same profile then the nodes from the model are returned.
@@ -108,7 +116,11 @@ struct BookmarkDragData {
private:
// Path of the profile we originated from.
+#if defined(WCHAR_T_IS_UTF16)
std::wstring profile_path_;
+#elif defined(WCHAR_T_IS_UTF32)
+ std::string profile_path_;
+#endif
};
-#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_
+#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_H_
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 649c2c64..01b95a2 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -9,7 +9,9 @@
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
+#include "base/pickle.h"
#include "chrome/browser/bookmarks/bookmark_context_menu.h"
+#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/bookmarks/bookmark_menu_controller_gtk.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
@@ -33,12 +35,31 @@ const int kBarPadding = 2;
// Maximum number of characters on a bookmark button.
const size_t kMaxCharsOnAButton = 15;
-// Our custom draging type for bookmarks.
-static GtkTargetEntry target_table[] = {
- { const_cast<char*>("application/x-bookmark-toolbar-item"),
- GTK_TARGET_SAME_APP, 0 }
+// Used in gtk_selection_data_set(). (I assume from this parameter that gtk has
+// to some really exotic hardware...)
+const int kBitsInAByte = 8;
+
+// Dictionary key used to store a BookmarkNode* on a GtkWidget.
+const char kBookmarkNode[] = "bookmark-node";
+
+// Integers representing the various types of items that the bookmark bar
+// accepts as DnD types.
+enum BookmarkType {
+ DROP_TARGET_INTERNAL
};
+// Mime types for DnD. Used to synchronize across applications.
+const char kInternalURIType[] = "application/x-chrome-bookmark-item";
+
+// Table of the mime types that we accept with their options.
+const GtkTargetEntry kTargetTable[] = {
+ { const_cast<char*>(kInternalURIType), GTK_TARGET_SAME_APP,
+ DROP_TARGET_INTERNAL }
+ // TODO(erg): Add "text/uri-list" support.
+};
+
+const int kTargetTableSize = G_N_ELEMENTS(kTargetTable);
+
} // namespace
BookmarkBarGtk::BookmarkBarGtk(Profile* profile, Browser* browser)
@@ -112,7 +133,7 @@ void BookmarkBarGtk::Init(Profile* profile) {
TRUE, TRUE, 0);
gtk_drag_dest_set(bookmark_toolbar_.get(), GTK_DEST_DEFAULT_DROP,
- target_table, G_N_ELEMENTS(target_table),
+ kTargetTable, kTargetTableSize,
GDK_ACTION_MOVE);
g_signal_connect(bookmark_toolbar_.get(), "drag-motion",
G_CALLBACK(&OnToolbarDragMotion), this);
@@ -120,6 +141,8 @@ void BookmarkBarGtk::Init(Profile* profile) {
G_CALLBACK(&OnToolbarDragLeave), this);
g_signal_connect(bookmark_toolbar_.get(), "drag-drop",
G_CALLBACK(&OnToolbarDragDrop), this);
+ g_signal_connect(bookmark_toolbar_.get(), "drag-data-received",
+ G_CALLBACK(&OnToolbarDragReceived), this);
g_signal_connect(bookmark_toolbar_.get(), "button-press-event",
G_CALLBACK(&OnButtonPressed), this);
@@ -318,6 +341,9 @@ void BookmarkBarGtk::ConfigureButtonForNode(BookmarkNode* node,
gtk_button_set_image(GTK_BUTTON(button),
gtk_image_new_from_pixbuf(default_bookmark_icon));
}
+
+ g_object_set_data(G_OBJECT(button), kBookmarkNode,
+ reinterpret_cast<void*>(node));
}
GtkWidget* BookmarkBarGtk::CreateBookmarkButton(
@@ -327,12 +353,17 @@ GtkWidget* BookmarkBarGtk::CreateBookmarkButton(
// The tool item is also a source for dragging
gtk_drag_source_set(button, GDK_BUTTON1_MASK,
- target_table, G_N_ELEMENTS(target_table),
+ kTargetTable, kTargetTableSize,
GDK_ACTION_MOVE);
g_signal_connect(G_OBJECT(button), "drag-begin",
G_CALLBACK(&OnButtonDragBegin), this);
g_signal_connect(G_OBJECT(button), "drag-end",
G_CALLBACK(&OnButtonDragEnd), this);
+ g_signal_connect(G_OBJECT(button), "drag-data-get",
+ G_CALLBACK(&OnButtonDragGet), this);
+ // We deliberately don't connect to "drag-data-delete" because the action of
+ // moving a button will regenerate all the contents of the bookmarks bar
+ // anyway.
if (node->is_url()) {
// Connect to 'button-release-event' instead of 'clicked' because we need
@@ -509,7 +540,8 @@ void BookmarkBarGtk::OnButtonDragBegin(GtkWidget* button,
gtk_container_add(GTK_CONTAINER(window), frame);
gtk_widget_show(frame);
- GtkWidget* floating_button = bar->CreateBookmarkButton(node);
+ GtkWidget* floating_button = gtk_chrome_button_new();
+ bar->ConfigureButtonForNode(node, floating_button);
gtk_container_add(GTK_CONTAINER(frame), floating_button);
gtk_widget_show(floating_button);
@@ -537,6 +569,34 @@ void BookmarkBarGtk::OnButtonDragEnd(GtkWidget* button,
}
// static
+void BookmarkBarGtk::OnButtonDragGet(GtkWidget* widget, GdkDragContext* context,
+ GtkSelectionData* selection_data,
+ guint target_type, guint time,
+ BookmarkBarGtk* bar) {
+ BookmarkNode* node =
+ reinterpret_cast<BookmarkNode*>(
+ g_object_get_data(G_OBJECT(widget), kBookmarkNode));
+ DCHECK(node);
+
+ switch (target_type) {
+ case DROP_TARGET_INTERNAL: {
+ BookmarkDragData data(node);
+ Pickle pickle;
+ data.WriteToPickle(bar->profile_, &pickle);
+
+ gtk_selection_data_set(selection_data, selection_data->target,
+ kBitsInAByte,
+ static_cast<const guchar*>(pickle.data()),
+ pickle.size());
+ break;
+ }
+ default: {
+ DLOG(ERROR) << "Unsupported drag get type!";
+ }
+ }
+}
+
+// static
gboolean BookmarkBarGtk::OnFolderButtonReleased(GtkWidget* sender,
GdkEventButton* event,
BookmarkBarGtk* bar) {
@@ -614,22 +674,63 @@ void BookmarkBarGtk::OnToolbarDragLeave(GtkToolbar* toolbar,
}
// static
-gboolean BookmarkBarGtk::OnToolbarDragDrop(GtkWidget* toolbar,
- GdkDragContext* drag_context,
- gint x,
- gint y,
- guint time,
+gboolean BookmarkBarGtk::OnToolbarDragDrop(
+ GtkWidget* widget, GdkDragContext* context,
+ gint x, gint y, guint time,
+ BookmarkBarGtk* bar) {
+ gboolean is_valid_drop_site = FALSE;
+
+ if (context->targets) {
+ GdkAtom target_type =
+ GDK_POINTER_TO_ATOM(g_list_nth_data(context->targets,
+ DROP_TARGET_INTERNAL));
+ gtk_drag_get_data(widget, context, target_type, time);
+
+ is_valid_drop_site = TRUE;
+ }
+
+ return is_valid_drop_site;
+}
+
+// static
+void BookmarkBarGtk::OnToolbarDragReceived(GtkWidget* widget,
+ GdkDragContext* context,
+ gint x, gint y,
+ GtkSelectionData* selection_data,
+ guint target_type, guint time,
BookmarkBarGtk* bar) {
- // TODO(erg): This implementation only works within the same profile, which
- // is OK for now because we're restricted to drags from within the same
- // window.
- if (bar->dragged_node_) {
- gint index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(toolbar), x, y);
- // Drag from same profile, do a move.
- bar->model_->Move(bar->dragged_node_, bar->model_->GetBookmarkBarNode(),
- index);
- return TRUE;
+ gboolean dnd_success = FALSE;
+ gboolean delete_selection_data = FALSE;
+
+ // Deal with what we are given from source
+ if ((selection_data != NULL) && (selection_data->length >= 0)) {
+ if (context-> action == GDK_ACTION_MOVE) {
+ delete_selection_data = TRUE;
+ }
+
+ switch (target_type) {
+ case DROP_TARGET_INTERNAL: {
+ Pickle pickle(reinterpret_cast<char*>(selection_data->data),
+ selection_data->length);
+ BookmarkDragData drag_data;
+ drag_data.ReadFromPickle(&pickle);
+
+ std::vector<BookmarkNode*> nodes = drag_data.GetNodes(bar->profile_);
+ for (std::vector<BookmarkNode*>::iterator it = nodes.begin();
+ it != nodes.end(); ++it) {
+ gint index = gtk_toolbar_get_drop_index(
+ GTK_TOOLBAR(bar->bookmark_toolbar_.get()), x, y);
+ bar->model_->Move(*it, bar->model_->GetBookmarkBarNode(), index);
+ }
+
+ dnd_success = TRUE;
+ break;
+ }
+ default: {
+ DLOG(ERROR) << "Unsupported drag received type: " << target_type;
+ }
+ }
}
- return FALSE;
+ 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 697b55c..72f42c6 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.h
+++ b/chrome/browser/gtk/bookmark_bar_gtk.h
@@ -137,6 +137,10 @@ class BookmarkBarGtk : public BookmarkModelObserver {
static void OnButtonDragEnd(GtkWidget* button,
GdkDragContext* drag_context,
BookmarkBarGtk* bar);
+ static void OnButtonDragGet(GtkWidget* widget, GdkDragContext* context,
+ GtkSelectionData* selection_data,
+ guint target_type, guint time,
+ BookmarkBarGtk* bar);
// GtkButton callbacks for folder buttons
static gboolean OnFolderButtonReleased(GtkWidget* sender,
@@ -156,11 +160,14 @@ class BookmarkBarGtk : public BookmarkModelObserver {
GdkDragContext* context,
guint time,
BookmarkBarGtk* bar);
- static gboolean OnToolbarDragDrop(GtkWidget* toolbar,
- GdkDragContext* drag_context,
- gint x,
- gint y,
- guint time,
+ static gboolean OnToolbarDragDrop(GtkWidget* widget, GdkDragContext* context,
+ gint x, gint y, 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);
Profile* profile_;