summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 22:03:00 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-06 22:03:00 +0000
commit29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c (patch)
tree6cc5dd709d48346ba0c6669f67263cbc714fbc9d /chrome/browser/gtk
parent901065b013787109038f232c0707b245af796599 (diff)
downloadchromium_src-29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c.zip
chromium_src-29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c.tar.gz
chromium_src-29cc841ee15bbb8b31baf7ece0b2a3e2d3b55b5c.tar.bz2
Clicking on a folder in the bookmark bar now shows its contents as a menu.
http://crbug.com/11250 Review URL: http://codereview.chromium.org/114005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15463 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc12
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.h5
-rw-r--r--chrome/browser/gtk/menu_gtk.cc108
-rw-r--r--chrome/browser/gtk/menu_gtk.h22
4 files changed, 127 insertions, 20 deletions
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 6c3d85f..9f4f0ce 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -8,6 +8,7 @@
#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
#include "chrome/browser/bookmarks/bookmark_context_menu.h"
+#include "chrome/browser/bookmarks/bookmark_menu_controller_gtk.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/custom_button.h"
@@ -353,6 +354,8 @@ GtkWidget* BookmarkBarGtk::CreateBookmarkButton(
GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(BookmarkNode* node) {
GtkWidget* button = CreateBookmarkButton(node);
+ g_object_set_data(G_OBJECT(button), "left-align-popup",
+ reinterpret_cast<void*>(true));
GtkToolItem* item = gtk_tool_item_new();
gtk_container_add(GTK_CONTAINER(item), button);
@@ -537,7 +540,14 @@ gboolean BookmarkBarGtk::OnFolderButtonReleased(GtkWidget* sender,
DCHECK(node);
DCHECK(bar->page_navigator_);
- NOTIMPLEMENTED() << "Flesh this out once I can make folders.";
+ bar->current_menu_.reset(
+ new BookmarkMenuController(bar->browser_, bar->profile_,
+ bar->page_navigator_,
+ GTK_WINDOW(gtk_widget_get_toplevel(sender)),
+ node,
+ 0,
+ false));
+ bar->current_menu_->Popup(sender, event->button, event->time);
// Allow other handlers to run so the button state is updated correctly.
return FALSE;
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h
index 17f508f..8c02765 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.h
+++ b/chrome/browser/gtk/bookmark_bar_gtk.h
@@ -14,6 +14,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
class BookmarkContextMenu;
+class BookmarkMenuController;
class Browser;
class CustomContainerButton;
class PageNavigator;
@@ -200,6 +201,10 @@ class BookmarkBarGtk : public BookmarkModelObserver {
// The last displayed right click menu, or NULL if no menus have been
// displayed yet.
scoped_ptr<BookmarkContextMenu> current_context_menu_;
+
+ // The last displayed left click menu, or NULL if no menus have been
+ // displayed yet.
+ scoped_ptr<BookmarkMenuController> current_menu_;
};
#endif // CHROME_BROWSER_GTK_BOOKMARK_BAR_GTK_H_
diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
index fd63e44..6d12f26 100644
--- a/chrome/browser/gtk/menu_gtk.cc
+++ b/chrome/browser/gtk/menu_gtk.cc
@@ -6,10 +6,36 @@
#include "app/l10n_util.h"
#include "base/logging.h"
+#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/common/gtk_util.h"
#include "skia/include/SkBitmap.h"
+namespace {
+
+struct SetIconState {
+ bool found;
+ const SkBitmap* icon;
+ int id;
+};
+
+void SetIconImpl(GtkWidget* widget, void* raw) {
+ SetIconState* data = reinterpret_cast<SetIconState*>(raw);
+ int this_id =
+ reinterpret_cast<int>(g_object_get_data(G_OBJECT(widget), "menu-id"));
+
+ if (this_id == data->id) {
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(data->icon);
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget),
+ gtk_image_new_from_pixbuf(pixbuf));
+ g_object_unref(pixbuf);
+
+ data->found = true;
+ }
+}
+
+} // namespace
+
MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
const MenuCreateMaterial* menu_data,
GtkAccelGroup* accel_group)
@@ -28,6 +54,7 @@ MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, bool load)
}
MenuGtk::~MenuGtk() {
+ STLDeleteElements(&children_);
menu_.Destroy();
if (dummy_accel_group_)
g_object_unref(dummy_accel_group_);
@@ -36,15 +63,28 @@ MenuGtk::~MenuGtk() {
void MenuGtk::AppendMenuItemWithLabel(int command_id,
const std::string& label) {
GtkWidget* menu_item = gtk_menu_item_new_with_label(label.c_str());
+ AddMenuItemWithId(menu_item, command_id);
+}
- g_object_set_data(G_OBJECT(menu_item), "menu-id",
- reinterpret_cast<void*>(command_id));
+void MenuGtk::AppendMenuItemWithIcon(int command_id,
+ const std::string& label,
+ const SkBitmap& icon) {
+ GtkWidget* menu_item = BuildMenuItemWithImage(label, icon);
+ AddMenuItemWithId(menu_item, command_id);
+}
- g_signal_connect(G_OBJECT(menu_item), "activate",
- G_CALLBACK(OnMenuItemActivatedById), this);
+MenuGtk* MenuGtk::AppendSubMenuWithIcon(int command_id,
+ const std::string& label,
+ const SkBitmap& icon) {
+ GtkWidget* menu_item = BuildMenuItemWithImage(label, icon);
- gtk_widget_show(menu_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
+ MenuGtk* submenu = new MenuGtk(delegate_, false);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu->menu_.get());
+ children_.push_back(submenu);
+
+ AddMenuItemWithId(menu_item, command_id);
+
+ return submenu;
}
void MenuGtk::AppendSeparator() {
@@ -82,6 +122,25 @@ void MenuGtk::Cancel() {
gtk_menu_popdown(GTK_MENU(menu_.get()));
}
+bool MenuGtk::SetIcon(const SkBitmap& icon, int item_id) {
+ // First search items in this menu.
+ SetIconState state;
+ state.found = false;
+ state.icon = &icon;
+ state.id = item_id;
+ gtk_container_foreach(GTK_CONTAINER(menu_.get()), SetIconImpl, &state);
+ if (state.found)
+ return true;
+
+ for (std::vector<MenuGtk*>::iterator it = children_.begin();
+ it != children_.end(); ++it) {
+ if ((*it)->SetIcon(icon, item_id))
+ return true;
+ }
+
+ return false;
+}
+
// static
std::string MenuGtk::ConvertAcceleratorsFromWindowsStyle(
const std::string& label) {
@@ -178,6 +237,18 @@ void MenuGtk::BuildMenuIn(GtkWidget* menu,
}
}
+GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
+ const SkBitmap& icon) {
+ GtkWidget* menu_item = gtk_image_menu_item_new_with_label(label.c_str());
+
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
+ gtk_image_new_from_pixbuf(pixbuf));
+ g_object_unref(pixbuf);
+
+ return menu_item;
+}
+
void MenuGtk::BuildMenuFromDelegate() {
// Note that the menu IDs start at 1, not 0.
for (int i = 1; i <= delegate_->GetItemCount(); ++i) {
@@ -186,26 +257,25 @@ void MenuGtk::BuildMenuFromDelegate() {
if (delegate_->IsItemSeparator(i)) {
menu_item = gtk_separator_menu_item_new();
} else if (delegate_->HasIcon(i)) {
- menu_item = gtk_image_menu_item_new_with_label(
- delegate_->GetLabel(i).c_str());
const SkBitmap* icon = delegate_->GetIcon(i);
- GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(icon);
- GtkWidget* widget = gtk_image_new_from_pixbuf(pixbuf);
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), widget);
- g_object_unref(pixbuf);
+ menu_item = BuildMenuItemWithImage(delegate_->GetLabel(i), *icon);
} else {
menu_item = gtk_menu_item_new_with_label(delegate_->GetLabel(i).c_str());
}
- g_object_set_data(G_OBJECT(menu_item), "menu-id",
- reinterpret_cast<void*>(i));
+ AddMenuItemWithId(menu_item, i);
+ }
+}
+
+void MenuGtk::AddMenuItemWithId(GtkWidget* menu_item, int id) {
+ g_object_set_data(G_OBJECT(menu_item), "menu-id",
+ reinterpret_cast<void*>(id));
- g_signal_connect(G_OBJECT(menu_item), "activate",
- G_CALLBACK(OnMenuItemActivatedById), this);
+ g_signal_connect(G_OBJECT(menu_item), "activate",
+ G_CALLBACK(OnMenuItemActivatedById), this);
- gtk_widget_show(menu_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
- }
+ gtk_widget_show(menu_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_.get()), menu_item);
}
// static
diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h
index 371ed58..b7afd67 100644
--- a/chrome/browser/gtk/menu_gtk.h
+++ b/chrome/browser/gtk/menu_gtk.h
@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include <string>
+#include <vector>
#include "chrome/browser/gtk/standard_menus.h"
#include "chrome/common/owned_widget_gtk.h"
@@ -48,6 +49,10 @@ class MenuGtk {
// These methods are used to build the menu dynamically.
void AppendMenuItemWithLabel(int command_id, const std::string& label);
+ void AppendMenuItemWithIcon(int command_id, const std::string& label,
+ const SkBitmap& icon);
+ MenuGtk* AppendSubMenuWithIcon(int command_id, const std::string& label,
+ const SkBitmap& icon);
void AppendSeparator();
// Displays the menu. |timestamp| is the time of activation. The popup is
@@ -67,6 +72,11 @@ class MenuGtk {
// Closes the menu.
void Cancel();
+ // Sets an icon for an item with a given item_id. This method searches both
+ // this MenuGtk object and all child submenus. Returns false if the item with
+ // |item_id| is not found.
+ bool SetIcon(const SkBitmap& icon, int item_id);
+
// Change windows accelerator style to GTK style. (GTK uses _ for
// accelerators. Windows uses & with && as an escape for &.)
static std::string ConvertAcceleratorsFromWindowsStyle(
@@ -79,10 +89,18 @@ class MenuGtk {
const MenuCreateMaterial* menu_data,
GtkAccelGroup* accel_group);
+ // Builds a GtkImageMenuItem.
+ GtkWidget* BuildMenuItemWithImage(const std::string& label,
+ const SkBitmap& icon);
+
// A function that creates a GtkMenu from |delegate_|. This function is not
// recursive and does not support sub-menus.
void BuildMenuFromDelegate();
+ // Helper method that sets properties on a GtkMenuItem and then adds it to
+ // our internal |menu_|.
+ void AddMenuItemWithId(GtkWidget* menu_item, int id);
+
// Callback for when a menu item is clicked. Used when the menu is created
// via a MenuCreateMaterial.
static void OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu);
@@ -116,6 +134,10 @@ class MenuGtk {
// gtk_menu_popup() does not appear to take ownership of popup menus, so
// MenuGtk explicitly manages the lifetime of the menu.
OwnedWidgetGtk menu_;
+
+ // MenuGtk instances of submenus; we keep references to these objects just to
+ // clean up during our destructor.
+ std::vector<MenuGtk*> children_;
};
#endif // CHROME_BROWSER_GTK_MENU_GTK_H_