146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// found in the LICENSE file. 446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h" 646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include <gtk/gtk.h> 846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/bind.h" 1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/debug/leak_annotations.h" 1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/ui/libgtk2ui/menu_util.h" 1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ui/base/models/menu_model.h" 1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace libgtk2ui { 1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)AppIndicatorIconMenu::AppIndicatorIconMenu(ui::MenuModel* model) 1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) : menu_model_(model), 1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) click_action_replacement_menu_item_added_(false), 1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_menu_(NULL), 2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) block_activation_(false) { 2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) { 2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/378770 2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_menu_ = gtk_menu_new(); 2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) g_object_ref_sink(gtk_menu_); 2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (menu_model_) { 2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) BuildSubmenuFromModel(menu_model_, 2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_menu_, 2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) G_CALLBACK(OnMenuItemActivatedThunk), 3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) &block_activation_, 3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) this); 3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) Refresh(); 3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)AppIndicatorIconMenu::~AppIndicatorIconMenu() { 3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_widget_destroy(gtk_menu_); 3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) g_object_unref(gtk_menu_); 3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppIndicatorIconMenu::UpdateClickActionReplacementMenuItem( 4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const char* label, 4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const base::Closure& callback) { 4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) click_action_replacement_callback_ = callback; 4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (click_action_replacement_menu_item_added_) { 4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_)); 4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for (GList* child = children; child; child = g_list_next(child)) { 4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (g_object_get_data(G_OBJECT(child->data), "click-action-item") != 5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) NULL) { 5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_menu_item_set_label(GTK_MENU_ITEM(child->data), label); 5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) break; 5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) g_list_free(children); 5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } else { 5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) click_action_replacement_menu_item_added_ = true; 5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // If |menu_model_| is non empty, add a separator to separate the 6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // "click action replacement menu item" from the other menu items. 6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (menu_model_ && menu_model_->GetItemCount() > 0) { 6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GtkWidget* menu_item = gtk_separator_menu_item_new(); 6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_widget_show(menu_item); 6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item); 6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(label); 6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) g_object_set_data( 6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) G_OBJECT(menu_item), "click-action-item", GINT_TO_POINTER(1)); 7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) g_signal_connect(menu_item, 7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) "activate", 7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) G_CALLBACK(OnClickActionReplacementMenuItemActivatedThunk), 7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) this); 7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_widget_show(menu_item); 7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_menu_shell_prepend(GTK_MENU_SHELL(gtk_menu_), menu_item); 7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppIndicatorIconMenu::Refresh() { 8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) gtk_container_foreach( 8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_); 8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)GtkMenu* AppIndicatorIconMenu::GetGtkMenu() { 8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return GTK_MENU(gtk_menu_); 8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppIndicatorIconMenu::OnClickActionReplacementMenuItemActivated( 9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) GtkWidget* menu_item) { 9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) click_action_replacement_callback_.Run(); 9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void AppIndicatorIconMenu::OnMenuItemActivated(GtkWidget* menu_item) { 9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (block_activation_) 9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ui::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menu_item)); 9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!model) { 10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // There won't be a model for "native" submenus like the "Input Methods" 10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // context menu. We don't need to handle activation messages for submenus 10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // anyway, so we can just return here. 10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DCHECK(gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))); 10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // The activate signal is sent to radio items as they get deselected; 10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // ignore it in this case. 10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (GTK_IS_RADIO_MENU_ITEM(menu_item) && 11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))) { 11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) int id; 11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!GetMenuItemID(menu_item, &id)) 11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // The menu item can still be activated by hotkeys even if it is disabled. 11946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (menu_model_->IsEnabledAt(id)) 12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ExecuteCommand(model, id); 12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} // namespace libgtk2ui 124