| Index: chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
|
| diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
|
| index 757052e1d0e064dbfc02a242f1cd20ac497dc6a3..7ef1c4087680f67ad14768846e9ff816480741bd 100644
|
| --- a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
|
| +++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
|
| @@ -13,10 +13,9 @@
|
| #include "base/strings/stringprintf.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/threading/sequenced_worker_pool.h"
|
| -#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h"
|
| +#include "chrome/browser/ui/libgtk2ui/menu_util.h"
|
| #include "content/public/browser/browser_thread.h"
|
| #include "ui/base/models/menu_model.h"
|
| -#include "ui/gfx/image/image.h"
|
| #include "ui/gfx/image/image_skia.h"
|
|
|
| namespace {
|
| @@ -168,8 +167,10 @@
|
| const base::string16& tool_tip)
|
| : id_(id),
|
| icon_(NULL),
|
| + gtk_menu_(NULL),
|
| menu_model_(NULL),
|
| icon_change_count_(0),
|
| + block_activation_(false),
|
| weak_factory_(this) {
|
| EnsureMethodsLoaded();
|
| tool_tip_ = base::UTF16ToUTF8(tool_tip);
|
| @@ -178,6 +179,8 @@
|
| AppIndicatorIcon::~AppIndicatorIcon() {
|
| if (icon_) {
|
| app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
|
| + if (gtk_menu_)
|
| + DestroyMenu();
|
| g_object_unref(icon_);
|
| content::BrowserThread::GetBlockingPool()->PostTask(
|
| FROM_HERE,
|
| @@ -221,13 +224,30 @@
|
| void AppIndicatorIcon::SetToolTip(const base::string16& tool_tip) {
|
| DCHECK(!tool_tip_.empty());
|
| tool_tip_ = base::UTF16ToUTF8(tool_tip);
|
| - UpdateClickActionReplacementMenuItem();
|
| +
|
| + // We can set the click action label only if the icon exists. Also we only
|
| + // need to update the label if it is shown and it's only shown if we are sure
|
| + // that there is a click action or if there is no menu.
|
| + if (icon_ && (delegate()->HasClickAction() || menu_model_ == NULL)) {
|
| + GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_));
|
| + for (GList* child = children; child; child = g_list_next(child))
|
| + if (g_object_get_data(G_OBJECT(child->data), "click-action-item") !=
|
| + NULL) {
|
| + gtk_menu_item_set_label(GTK_MENU_ITEM(child->data),
|
| + tool_tip_.c_str());
|
| + break;
|
| + }
|
| + g_list_free(children);
|
| + }
|
| }
|
|
|
| void AppIndicatorIcon::UpdatePlatformContextMenu(ui::MenuModel* model) {
|
| if (!g_opened)
|
| return;
|
|
|
| + if (gtk_menu_) {
|
| + DestroyMenu();
|
| + }
|
| menu_model_ = model;
|
|
|
| // The icon is created asynchronously so it might not exist when the menu is
|
| @@ -237,7 +257,8 @@
|
| }
|
|
|
| void AppIndicatorIcon::RefreshPlatformContextMenu() {
|
| - menu_->Refresh();
|
| + gtk_container_foreach(
|
| + GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
|
| }
|
|
|
| void AppIndicatorIcon::SetImageFromFile(const base::FilePath& icon_file_path) {
|
| @@ -273,29 +294,78 @@
|
| }
|
|
|
| void AppIndicatorIcon::SetMenu() {
|
| - menu_.reset(new AppIndicatorIconMenu(menu_model_));
|
| - UpdateClickActionReplacementMenuItem();
|
| - app_indicator_set_menu(icon_, menu_->GetGtkMenu());
|
| -}
|
| -
|
| -void AppIndicatorIcon::UpdateClickActionReplacementMenuItem() {
|
| - // The menu may not have been created yet.
|
| - if (!menu_.get())
|
| - return;
|
| -
|
| - if (!delegate()->HasClickAction() && menu_model_)
|
| - return;
|
| -
|
| + gtk_menu_ = gtk_menu_new();
|
| +
|
| + if (delegate()->HasClickAction() || menu_model_ == NULL) {
|
| + CreateClickActionReplacement();
|
| + if (menu_model_) {
|
| + // Add separator before the other menu items.
|
| + GtkWidget* menu_item = gtk_separator_menu_item_new();
|
| + gtk_widget_show(menu_item);
|
| + gtk_menu_shell_append(GTK_MENU_SHELL(gtk_menu_), menu_item);
|
| + }
|
| + }
|
| + if (menu_model_) {
|
| + BuildSubmenuFromModel(menu_model_,
|
| + gtk_menu_,
|
| + G_CALLBACK(OnMenuItemActivatedThunk),
|
| + &block_activation_,
|
| + this);
|
| + RefreshPlatformContextMenu();
|
| + }
|
| + app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
|
| +}
|
| +
|
| +void AppIndicatorIcon::CreateClickActionReplacement() {
|
| DCHECK(!tool_tip_.empty());
|
| - menu_->UpdateClickActionReplacementMenuItem(
|
| - tool_tip_.c_str(),
|
| - base::Bind(&AppIndicatorIcon::OnClickActionReplacementMenuItemActivated,
|
| - base::Unretained(this)));
|
| -}
|
| -
|
| -void AppIndicatorIcon::OnClickActionReplacementMenuItemActivated() {
|
| +
|
| + // Add "click replacement menu item".
|
| + GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(tool_tip_.c_str());
|
| + g_object_set_data(
|
| + G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1));
|
| + g_signal_connect(menu_item, "activate", G_CALLBACK(OnClickThunk), this);
|
| + gtk_widget_show(menu_item);
|
| + gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item);
|
| +}
|
| +
|
| +void AppIndicatorIcon::DestroyMenu() {
|
| + gtk_widget_destroy(gtk_menu_);
|
| + gtk_menu_ = NULL;
|
| + menu_model_ = NULL;
|
| +}
|
| +
|
| +void AppIndicatorIcon::OnClick(GtkWidget* menu_item) {
|
| if (delegate())
|
| delegate()->OnClick();
|
| }
|
|
|
| +void AppIndicatorIcon::OnMenuItemActivated(GtkWidget* menu_item) {
|
| + if (block_activation_)
|
| + return;
|
| +
|
| + ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item));
|
| + if (!model) {
|
| + // There won't be a model for "native" submenus like the "Input Methods"
|
| + // context menu. We don't need to handle activation messages for submenus
|
| + // anyway, so we can just return here.
|
| + DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item)));
|
| + return;
|
| + }
|
| +
|
| + // The activate signal is sent to radio items as they get deselected;
|
| + // ignore it in this case.
|
| + if (GTK_IS_RADIO_MENU_ITEM(menu_item) &&
|
| + !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) {
|
| + return;
|
| + }
|
| +
|
| + int id;
|
| + if (!GetMenuItemID(menu_item, &id))
|
| + return;
|
| +
|
| + // The menu item can still be activated by hotkeys even if it is disabled.
|
| + if (menu_model_->IsEnabledAt(id))
|
| + ExecuteCommand(model, id);
|
| +}
|
| +
|
| } // namespace libgtk2ui
|
|
|