Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4405)

Unified Diff: chrome/browser/gtk/browser_actions_toolbar_gtk.cc

Issue 463056: GTK: hook up drag and drop of browser actions (for reordering).... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/gtk/browser_actions_toolbar_gtk.h ('k') | chrome/common/gtk_util.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/gtk/browser_actions_toolbar_gtk.cc
===================================================================
--- chrome/browser/gtk/browser_actions_toolbar_gtk.cc (revision 34134)
+++ chrome/browser/gtk/browser_actions_toolbar_gtk.cc (working copy)
@@ -4,7 +4,6 @@
#include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
-#include <gtk/gtk.h>
#include <vector>
#include "app/gfx/canvas_paint.h"
@@ -26,14 +25,29 @@
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
+namespace {
+
// The size of each button on the toolbar.
-static const int kButtonSize = 29;
+const int kButtonSize = 29;
// The padding between browser action buttons. Visually, the actual number of
// "empty" (non-drawing) pixels is this value + 2 when adjacent browser icons
// use their maximum allowed size.
-static const int kBrowserActionButtonPadding = 3;
+const int kButtonPadding = 3;
+const char* kDragTarget = "application/x-chrome-browseraction";
+
+GtkTargetEntry GetDragTargetEntry() {
+ static std::string drag_target_string(kDragTarget);
+ GtkTargetEntry drag_target;
+ drag_target.target = const_cast<char*>(drag_target_string.c_str());
+ drag_target.flags = GTK_TARGET_SAME_APP;
+ drag_target.info = 0;
+ return drag_target;
+}
+
+} // namespace
+
class BrowserActionButton : public NotificationObserver,
public ImageLoadingTracker::Observer {
public:
@@ -61,11 +75,12 @@
Extension::kBrowserActionIconMaxSize));
}
- // We need to hook up extension popups here. http://crbug.com/23897
g_signal_connect(button_.get(), "clicked",
G_CALLBACK(OnButtonClicked), this);
g_signal_connect_after(button_.get(), "expose-event",
G_CALLBACK(OnExposeEvent), this);
+ g_signal_connect(button_.get(), "drag-begin",
+ G_CALLBACK(&OnDragBegin), this);
registrar_.Add(this, NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
Source<ExtensionAction>(extension->browser_action()));
@@ -90,6 +105,9 @@
GtkWidget* widget() { return button_.get(); }
+ Extension* extension() { return extension_; }
+
+ // NotificationObserver implementation.
void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -148,16 +166,16 @@
}
static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) {
- if (action->extension_->browser_action()->has_popup()) {
- ExtensionPopupGtk::Show(
- action->extension_->browser_action()->popup_url(),
- action->toolbar_->browser(),
- gtk_util::GetWidgetRectRelativeToToplevel(widget));
- } else {
- ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
- action->toolbar_->browser()->profile(), action->extension_->id(),
- action->toolbar_->browser());
- }
+ if (action->extension_->browser_action()->has_popup()) {
+ ExtensionPopupGtk::Show(
+ action->extension_->browser_action()->popup_url(),
+ action->toolbar_->browser(),
+ gtk_util::GetWidgetRectRelativeToToplevel(widget));
+ } else {
+ ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
+ action->toolbar_->browser()->profile(), action->extension_->id(),
+ action->toolbar_->browser());
+ }
}
static gboolean OnExposeEvent(GtkWidget* widget,
@@ -177,6 +195,15 @@
return FALSE;
}
+ static void OnDragBegin(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ BrowserActionButton* button) {
+ // Simply pass along the notification to the toolbar. The point of this
+ // function is to tell the toolbar which BrowserActionButton initiated the
+ // drag.
+ button->toolbar_->DragStarted(button, drag_context);
+ }
+
// The toolbar containing this button.
BrowserActionsToolbarGtk* toolbar_;
@@ -204,14 +231,18 @@
: browser_(browser),
profile_(browser->profile()),
model_(NULL),
- hbox_(gtk_hbox_new(FALSE, kBrowserActionButtonPadding)) {
+ hbox_(gtk_hbox_new(FALSE, kButtonPadding)),
+ drag_button_(NULL),
+ drop_index_(-1) {
ExtensionsService* extension_service = profile_->GetExtensionsService();
// The |extension_service| can be NULL in Incognito.
- if (extension_service) {
- model_ = extension_service->toolbar_model();
- model_->AddObserver(this);
- CreateAllButtons();
- }
+ if (!extension_service)
+ return;
+
+ model_ = extension_service->toolbar_model();
+ model_->AddObserver(this);
+ SetupDrags();
+ CreateAllButtons();
}
BrowserActionsToolbarGtk::~BrowserActionsToolbarGtk() {
@@ -235,21 +266,42 @@
}
}
+void BrowserActionsToolbarGtk::SetupDrags() {
+ GtkTargetEntry drag_target = GetDragTargetEntry();
+ gtk_drag_dest_set(widget(), GTK_DEST_DEFAULT_DROP, &drag_target, 1,
+ GDK_ACTION_MOVE);
+
+ g_signal_connect(widget(), "drag-motion",
+ G_CALLBACK(OnDragMotionThunk), this);
+}
+
void BrowserActionsToolbarGtk::CreateAllButtons() {
+ extension_button_map_.clear();
+
+ int i = 0;
for (ExtensionList::iterator iter = model_->begin();
iter != model_->end(); ++iter) {
- CreateButtonForExtension(*iter);
+ CreateButtonForExtension(*iter, i++);
}
}
-void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension) {
+void BrowserActionsToolbarGtk::CreateButtonForExtension(Extension* extension,
+ int index) {
RemoveButtonForExtension(extension);
linked_ptr<BrowserActionButton> button(
new BrowserActionButton(this, extension));
- gtk_box_pack_end(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox_.get()), button->widget(), FALSE, FALSE, 0);
+ gtk_box_reorder_child(GTK_BOX(hbox_.get()), button->widget(), index);
gtk_widget_show(button->widget());
extension_button_map_[extension->id()] = button;
+ GtkTargetEntry drag_target = GetDragTargetEntry();
+ gtk_drag_source_set(button->widget(), GDK_BUTTON1_MASK, &drag_target, 1,
+ GDK_ACTION_MOVE);
+ // We ignore whether the drag was a "success" or "failure" in Gtk's opinion.
+ g_signal_connect(button->widget(), "drag-end",
+ G_CALLBACK(&OnDragEndThunk), this);
+
UpdateVisibility();
}
@@ -267,10 +319,68 @@
void BrowserActionsToolbarGtk::BrowserActionAdded(Extension* extension,
int index) {
- // TODO(estade): respect |index|.
- CreateButtonForExtension(extension);
+ CreateButtonForExtension(extension, index);
}
void BrowserActionsToolbarGtk::BrowserActionRemoved(Extension* extension) {
+ if (drag_button_ != NULL) {
+ // Break the current drag.
+ gtk_grab_remove(widget());
+
+ // Re-generate the toolbar to clean up unfinished drag business (i.e., we
+ // may have re-ordered some buttons; this will put them back where they
+ // belong).
+ CreateAllButtons();
+ }
+
RemoveButtonForExtension(extension);
}
+
+void BrowserActionsToolbarGtk::BrowserActionMoved(Extension* extension,
+ int index) {
+ // We initiated this move action, and have already moved the button.
+ if (drag_button_ != NULL)
+ return;
+
+ BrowserActionButton* button = extension_button_map_[extension->id()].get();
+ if (!button) {
+ NOTREACHED();
+ return;
+ }
+
+ gtk_box_reorder_child(GTK_BOX(hbox_.get()), button->widget(), index);
+}
+
+void BrowserActionsToolbarGtk::DragStarted(BrowserActionButton* button,
+ GdkDragContext* drag_context) {
+ // No representation of the widget following the cursor.
+ GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+ gtk_drag_set_icon_pixbuf(drag_context, pixbuf, 0, 0);
+ g_object_unref(pixbuf);
+
+ DCHECK(!drag_button_);
+ drag_button_ = button;
+}
+
+gboolean BrowserActionsToolbarGtk::OnDragMotion(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x, gint y, guint time) {
+ drop_index_ = x < kButtonSize ? 0 : x / (kButtonSize + kButtonPadding);
+ // We will go ahead and reorder the child in order to provide visual feedback
+ // to the user. We don't inform the model that it has moved until the drag
+ // ends.
+ gtk_box_reorder_child(GTK_BOX(hbox_.get()), drag_button_->widget(),
+ drop_index_);
+
+ gdk_drag_status(drag_context, GDK_ACTION_MOVE, time);
+ return TRUE;
+}
+
+void BrowserActionsToolbarGtk::OnDragEnd(GtkWidget* button,
+ GdkDragContext* drag_context) {
+ if (drop_index_ != -1)
+ model_->MoveBrowserAction(drag_button_->extension(), drop_index_);
+
+ drag_button_ = NULL;
+ drop_index_ = -1;
+}
« no previous file with comments | « chrome/browser/gtk/browser_actions_toolbar_gtk.h ('k') | chrome/common/gtk_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698