| Index: chrome/browser/gtk/menu_gtk.cc
|
| diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc
|
| index 6c24fd8c9070310168df9b5c2c9e5193f3880e92..104b39fbf913ebaa29bba71fa3696e05d33a0686 100644
|
| --- a/chrome/browser/gtk/menu_gtk.cc
|
| +++ b/chrome/browser/gtk/menu_gtk.cc
|
| @@ -8,17 +8,22 @@
|
|
|
| #include "app/l10n_util.h"
|
| #include "app/menus/accelerator_gtk.h"
|
| +#include "app/menus/button_menu_item_model.h"
|
| #include "app/menus/menu_model.h"
|
| +#include "app/resource_bundle.h"
|
| #include "base/i18n/rtl.h"
|
| #include "base/logging.h"
|
| #include "base/message_loop.h"
|
| #include "base/stl_util-inl.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "chrome/browser/gtk/gtk_custom_menu.h"
|
| +#include "chrome/browser/gtk/gtk_custom_menu_item.h"
|
| #include "chrome/browser/gtk/gtk_util.h"
|
| #include "gfx/gtk_util.h"
|
| #include "third_party/skia/include/core/SkBitmap.h"
|
|
|
| using gtk_util::ConvertAcceleratorsFromWindowsStyle;
|
| +using gtk_util::RemoveWindowsStyleAccelerators;
|
|
|
| bool MenuGtk::block_activation_ = false;
|
|
|
| @@ -99,7 +104,7 @@ MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
|
| : delegate_(delegate),
|
| model_(model),
|
| dummy_accel_group_(gtk_accel_group_new()),
|
| - menu_(gtk_menu_new()),
|
| + menu_(gtk_custom_menu_new()),
|
| factory_(this) {
|
| DCHECK(model);
|
| g_object_ref_sink(menu_);
|
| @@ -156,15 +161,20 @@ GtkWidget* MenuGtk::AppendSeparator() {
|
| }
|
|
|
| GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
|
| - return AppendMenuItemToMenu(command_id, menu_item, menu_);
|
| + return AppendMenuItemToMenu(command_id, menu_item, menu_, true);
|
| }
|
|
|
| GtkWidget* MenuGtk::AppendMenuItemToMenu(int command_id,
|
| GtkWidget* menu_item,
|
| - GtkWidget* menu) {
|
| - SetMenuItemID(menu_item, command_id);
|
| - g_signal_connect(menu_item, "activate",
|
| - G_CALLBACK(OnMenuItemActivated), this);
|
| + GtkWidget* menu,
|
| + bool connect_to_activate) {
|
| + // Native menu items do their own thing, so only selectively listen for the
|
| + // activate signal.
|
| + if (connect_to_activate) {
|
| + SetMenuItemID(menu_item, command_id);
|
| + g_signal_connect(menu_item, "activate",
|
| + G_CALLBACK(OnMenuItemActivated), this);
|
| + }
|
|
|
| gtk_widget_show(menu_item);
|
| gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
|
| @@ -231,6 +241,7 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
|
| SkBitmap icon;
|
| std::string label =
|
| ConvertAcceleratorsFromWindowsStyle(UTF16ToUTF8(model->GetLabelAt(i)));
|
| + bool connect_to_activate = true;
|
|
|
| switch (model->GetTypeAt(i)) {
|
| case menus::MenuModel::TYPE_SEPARATOR:
|
| @@ -255,6 +266,15 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
|
| }
|
| break;
|
| }
|
| + case menus::MenuModel::TYPE_BUTTON_ITEM: {
|
| + menus::ButtonMenuItemModel* button_menu_item_model =
|
| + model->GetButtonMenuItemAt(i);
|
| +
|
| + menu_item = BuildButtomMenuItem(button_menu_item_model);
|
| +
|
| + connect_to_activate = false;
|
| + break;
|
| + }
|
| case menus::MenuModel::TYPE_SUBMENU:
|
| case menus::MenuModel::TYPE_COMMAND:
|
| if (model->GetIconAt(i, &icon))
|
| @@ -285,7 +305,7 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
|
|
|
| g_object_set_data(G_OBJECT(menu_item), "model",
|
| reinterpret_cast<void*>(model));
|
| - AppendMenuItemToMenu(i, menu_item, menu);
|
| + AppendMenuItemToMenu(i, menu_item, menu, connect_to_activate);
|
|
|
| if (model->IsLabelDynamicAt(i)) {
|
| g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShow),
|
| @@ -296,6 +316,50 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
|
| }
|
| }
|
|
|
| +GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model) {
|
| + GtkWidget* menu_item = gtk_custom_menu_item_new(
|
| + RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str());
|
| + for (int i = 0; i < model->GetItemCount(); ++i) {
|
| + switch (model->GetTypeAt(i)) {
|
| + case menus::ButtonMenuItemModel::TYPE_SPACE: {
|
| + gtk_custom_menu_item_add_space(GTK_CUSTOM_MENU_ITEM(menu_item));
|
| + break;
|
| + }
|
| + case menus::ButtonMenuItemModel::TYPE_BUTTON: {
|
| + GtkWidget* button = gtk_custom_menu_item_add_button(
|
| + GTK_CUSTOM_MENU_ITEM(menu_item),
|
| + model->GetCommandIdAt(i));
|
| +
|
| + int icon_idr;
|
| + if (model->GetIconAt(i, &icon_idr)) {
|
| + // TODO(erg): This should go through the GtkThemeProvider so we can
|
| + // get a version tinted to label color.
|
| + gtk_button_set_image(
|
| + GTK_BUTTON(button),
|
| + gtk_image_new_from_pixbuf(
|
| + ResourceBundle::GetSharedInstance().
|
| + GetPixbufNamed(icon_idr)));
|
| + } else {
|
| + gtk_button_set_label(
|
| + GTK_BUTTON(button),
|
| + RemoveWindowsStyleAccelerators(
|
| + UTF16ToUTF8(model->GetLabelAt(i))).c_str());
|
| + }
|
| +
|
| + // TODO(erg): Set up dynamic labels here.
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Set up the callback to the model for when it is clicked.
|
| + g_object_set_data(G_OBJECT(menu_item), "button-model",
|
| + reinterpret_cast<void*>(model));
|
| + g_signal_connect(menu_item, "button-pushed",
|
| + G_CALLBACK(OnMenuButtonPressed), this);
|
| + return menu_item;
|
| +}
|
| +
|
| // static
|
| void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
|
| if (block_activation_)
|
| @@ -324,6 +388,19 @@ void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) {
|
| menu->ExecuteCommand(model, id);
|
| }
|
|
|
| +void MenuGtk::OnMenuButtonPressed(GtkMenuItem* menu_item, int command_id,
|
| + MenuGtk* menu) {
|
| + menus::ButtonMenuItemModel* model =
|
| + reinterpret_cast<menus::ButtonMenuItemModel*>(
|
| + g_object_get_data(G_OBJECT(menu_item), "button-model"));
|
| + if (model) {
|
| + if (menu->delegate_)
|
| + menu->delegate_->CommandWillBeExecuted();
|
| +
|
| + model->ActivatedCommand(command_id);
|
| + }
|
| +}
|
| +
|
| // static
|
| void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu,
|
| int* x,
|
|
|