| Index: chrome/browser/gtk/menu_gtk.cc
|
| ===================================================================
|
| --- chrome/browser/gtk/menu_gtk.cc (revision 71352)
|
| +++ chrome/browser/gtk/menu_gtk.cc (working copy)
|
| @@ -1,840 +0,0 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/gtk/menu_gtk.h"
|
| -
|
| -#include <map>
|
| -
|
| -#include "app/menus/accelerator_gtk.h"
|
| -#include "app/menus/button_menu_item_model.h"
|
| -#include "app/menus/menu_model.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/app/chrome_command_ids.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"
|
| -#include "webkit/glue/window_open_disposition.h"
|
| -
|
| -bool MenuGtk::block_activation_ = false;
|
| -
|
| -namespace {
|
| -
|
| -// Sets the ID of a menu item.
|
| -void SetMenuItemID(GtkWidget* menu_item, int menu_id) {
|
| - DCHECK_GE(menu_id, 0);
|
| -
|
| - // Add 1 to the menu_id to avoid setting zero (null) to "menu-id".
|
| - g_object_set_data(G_OBJECT(menu_item), "menu-id",
|
| - GINT_TO_POINTER(menu_id + 1));
|
| -}
|
| -
|
| -// Gets the ID of a menu item.
|
| -// Returns true if the menu item has an ID.
|
| -bool GetMenuItemID(GtkWidget* menu_item, int* menu_id) {
|
| - gpointer id_ptr = g_object_get_data(G_OBJECT(menu_item), "menu-id");
|
| - if (id_ptr != NULL) {
|
| - *menu_id = GPOINTER_TO_INT(id_ptr) - 1;
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -menus::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) {
|
| - return reinterpret_cast<menus::MenuModel*>(
|
| - g_object_get_data(G_OBJECT(menu_item), "model"));
|
| -}
|
| -
|
| -void SetupButtonShowHandler(GtkWidget* button,
|
| - menus::ButtonMenuItemModel* model,
|
| - int index) {
|
| - g_object_set_data(G_OBJECT(button), "button-model",
|
| - model);
|
| - g_object_set_data(G_OBJECT(button), "button-model-id",
|
| - GINT_TO_POINTER(index));
|
| -}
|
| -
|
| -void OnSubmenuShowButtonImage(GtkWidget* widget, GtkButton* button) {
|
| - MenuGtk::Delegate* delegate = reinterpret_cast<MenuGtk::Delegate*>(
|
| - g_object_get_data(G_OBJECT(button), "menu-gtk-delegate"));
|
| - int icon_idr = GPOINTER_TO_INT(g_object_get_data(
|
| - G_OBJECT(button), "button-image-idr"));
|
| -
|
| - GtkIconSet* icon_set = delegate->GetIconSetForId(icon_idr);
|
| - if (icon_set) {
|
| - gtk_button_set_image(
|
| - button, gtk_image_new_from_icon_set(icon_set,
|
| - GTK_ICON_SIZE_MENU));
|
| - }
|
| -}
|
| -
|
| -void SetupImageIcon(GtkWidget* button,
|
| - GtkWidget* menu,
|
| - int icon_idr,
|
| - MenuGtk::Delegate* menu_gtk_delegate) {
|
| - g_object_set_data(G_OBJECT(button), "button-image-idr",
|
| - GINT_TO_POINTER(icon_idr));
|
| - g_object_set_data(G_OBJECT(button), "menu-gtk-delegate",
|
| - menu_gtk_delegate);
|
| -
|
| - g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShowButtonImage), button);
|
| -}
|
| -
|
| -// Popup menus may get squished if they open up too close to the bottom of the
|
| -// screen. This function takes the size of the screen, the size of the menu,
|
| -// an optional widget, the Y position of the mouse click, and adjusts the popup
|
| -// menu's Y position to make it fit if it's possible to do so.
|
| -// Returns the new Y position of the popup menu.
|
| -int CalculateMenuYPosition(const GdkRectangle* screen_rect,
|
| - const GtkRequisition* menu_req,
|
| - const GtkWidget* widget, const int y) {
|
| - CHECK(screen_rect);
|
| - CHECK(menu_req);
|
| - // If the menu would run off the bottom of the screen, and there is enough
|
| - // screen space upwards to accommodate the menu, then pop upwards. If there
|
| - // is a widget, then also move the anchor point to the top of the widget
|
| - // rather than the bottom.
|
| - const int screen_top = screen_rect->y;
|
| - const int screen_bottom = screen_rect->y + screen_rect->height;
|
| - const int menu_bottom = y + menu_req->height;
|
| - int alternate_y = y - menu_req->height;
|
| - if (widget)
|
| - alternate_y -= widget->allocation.height;
|
| - if (menu_bottom >= screen_bottom && alternate_y >= screen_top)
|
| - return alternate_y;
|
| - return y;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -GtkWidget* MenuGtk::Delegate::GetDefaultImageForCommandId(int command_id) {
|
| - const char* stock;
|
| - switch (command_id) {
|
| - case IDC_NEW_TAB:
|
| - case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
|
| - case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
|
| - case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
|
| - stock = GTK_STOCK_NEW;
|
| - break;
|
| -
|
| - case IDC_CLOSE_TAB:
|
| - stock = GTK_STOCK_CLOSE;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
|
| - case IDC_CONTENT_CONTEXT_SAVEAVAS:
|
| - case IDC_CONTENT_CONTEXT_SAVELINKAS:
|
| - stock = GTK_STOCK_SAVE_AS;
|
| - break;
|
| -
|
| - case IDC_SAVE_PAGE:
|
| - stock = GTK_STOCK_SAVE;
|
| - break;
|
| -
|
| - case IDC_COPY:
|
| - case IDC_COPY_URL:
|
| - case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
|
| - case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
|
| - case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
|
| - case IDC_CONTENT_CONTEXT_COPYEMAILADDRESS:
|
| - case IDC_CONTENT_CONTEXT_COPY:
|
| - stock = GTK_STOCK_COPY;
|
| - break;
|
| -
|
| - case IDC_CUT:
|
| - case IDC_CONTENT_CONTEXT_CUT:
|
| - stock = GTK_STOCK_CUT;
|
| - break;
|
| -
|
| - case IDC_PASTE:
|
| - case IDC_CONTENT_CONTEXT_PASTE:
|
| - stock = GTK_STOCK_PASTE;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_DELETE:
|
| - case IDC_BOOKMARK_BAR_REMOVE:
|
| - stock = GTK_STOCK_DELETE;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_UNDO:
|
| - stock = GTK_STOCK_UNDO;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_REDO:
|
| - stock = GTK_STOCK_REDO;
|
| - break;
|
| -
|
| - case IDC_SEARCH:
|
| - case IDC_FIND:
|
| - case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
|
| - stock = GTK_STOCK_FIND;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_SELECTALL:
|
| - stock = GTK_STOCK_SELECT_ALL;
|
| - break;
|
| -
|
| - case IDC_CLEAR_BROWSING_DATA:
|
| - stock = GTK_STOCK_CLEAR;
|
| - break;
|
| -
|
| - case IDC_BACK:
|
| - stock = GTK_STOCK_GO_BACK;
|
| - break;
|
| -
|
| - case IDC_RELOAD:
|
| - stock = GTK_STOCK_REFRESH;
|
| - break;
|
| -
|
| - case IDC_FORWARD:
|
| - stock = GTK_STOCK_GO_FORWARD;
|
| - break;
|
| -
|
| - case IDC_PRINT:
|
| - stock = GTK_STOCK_PRINT;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
|
| - stock = GTK_STOCK_INFO;
|
| - break;
|
| -
|
| - case IDC_SPELLCHECK_MENU:
|
| - stock = GTK_STOCK_SPELL_CHECK;
|
| - break;
|
| -
|
| - case IDC_RESTORE_TAB:
|
| - stock = GTK_STOCK_UNDELETE;
|
| - break;
|
| -
|
| - case IDC_HOME:
|
| - stock = GTK_STOCK_HOME;
|
| - break;
|
| -
|
| - case IDC_STOP:
|
| - stock = GTK_STOCK_STOP;
|
| - break;
|
| -
|
| - case IDC_ABOUT:
|
| - stock = GTK_STOCK_ABOUT;
|
| - break;
|
| -
|
| - case IDC_EXIT:
|
| - stock = GTK_STOCK_QUIT;
|
| - break;
|
| -
|
| - case IDC_HELP_PAGE:
|
| - stock = GTK_STOCK_HELP;
|
| - break;
|
| -
|
| - case IDC_OPTIONS:
|
| - stock = GTK_STOCK_PREFERENCES;
|
| - break;
|
| -
|
| - case IDC_CONTENT_CONTEXT_GOTOURL:
|
| - stock = GTK_STOCK_JUMP_TO;
|
| - break;
|
| -
|
| - case IDC_DEV_TOOLS_INSPECT:
|
| - case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
|
| - stock = GTK_STOCK_PROPERTIES;
|
| - break;
|
| -
|
| - case IDC_BOOKMARK_BAR_ADD_NEW_BOOKMARK:
|
| - stock = GTK_STOCK_ADD;
|
| - break;
|
| -
|
| - case IDC_BOOKMARK_BAR_RENAME_FOLDER:
|
| - case IDC_BOOKMARK_BAR_EDIT:
|
| - stock = GTK_STOCK_EDIT;
|
| - break;
|
| -
|
| - case IDC_BOOKMARK_BAR_NEW_FOLDER:
|
| - stock = GTK_STOCK_DIRECTORY;
|
| - break;
|
| -
|
| - case IDC_BOOKMARK_BAR_OPEN_ALL:
|
| - stock = GTK_STOCK_OPEN;
|
| - break;
|
| -
|
| - default:
|
| - stock = NULL;
|
| - }
|
| -
|
| - return stock ? gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU) : NULL;
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::Delegate::GetImageForCommandId(int command_id) const {
|
| - return GetDefaultImageForCommandId(command_id);
|
| -}
|
| -
|
| -MenuGtk::MenuGtk(MenuGtk::Delegate* delegate,
|
| - menus::MenuModel* model)
|
| - : delegate_(delegate),
|
| - model_(model),
|
| - dummy_accel_group_(gtk_accel_group_new()),
|
| - menu_(gtk_custom_menu_new()),
|
| - factory_(this) {
|
| - DCHECK(model);
|
| - g_object_ref_sink(menu_);
|
| - ConnectSignalHandlers();
|
| - BuildMenuFromModel();
|
| -}
|
| -
|
| -MenuGtk::~MenuGtk() {
|
| - Cancel();
|
| -
|
| - gtk_widget_destroy(menu_);
|
| - g_object_unref(menu_);
|
| -
|
| - STLDeleteContainerPointers(submenus_we_own_.begin(), submenus_we_own_.end());
|
| - g_object_unref(dummy_accel_group_);
|
| -}
|
| -
|
| -void MenuGtk::ConnectSignalHandlers() {
|
| - // We connect afterwards because OnMenuShow calls SetMenuItemInfo, which may
|
| - // take a long time or even start a nested message loop.
|
| - g_signal_connect(menu_, "show", G_CALLBACK(OnMenuShowThunk), this);
|
| - g_signal_connect(menu_, "hide", G_CALLBACK(OnMenuHiddenThunk), this);
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::AppendMenuItemWithLabel(int command_id,
|
| - const std::string& label) {
|
| - std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label);
|
| - GtkWidget* menu_item = BuildMenuItemWithLabel(label, command_id);
|
| - return AppendMenuItem(command_id, menu_item);
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::AppendMenuItemWithIcon(int command_id,
|
| - const std::string& label,
|
| - const SkBitmap& icon) {
|
| - std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label);
|
| - GtkWidget* menu_item = BuildMenuItemWithImage(converted_label, icon);
|
| - return AppendMenuItem(command_id, menu_item);
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::AppendCheckMenuItemWithLabel(int command_id,
|
| - const std::string& label) {
|
| - std::string converted_label = gfx::ConvertAcceleratorsFromWindowsStyle(label);
|
| - GtkWidget* menu_item =
|
| - gtk_check_menu_item_new_with_mnemonic(converted_label.c_str());
|
| - return AppendMenuItem(command_id, menu_item);
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::AppendSeparator() {
|
| - GtkWidget* menu_item = gtk_separator_menu_item_new();
|
| - gtk_widget_show(menu_item);
|
| - gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item);
|
| - return menu_item;
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::AppendMenuItem(int command_id, GtkWidget* menu_item) {
|
| - if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) &&
|
| - GTK_IS_IMAGE_MENU_ITEM(menu_item))
|
| - gtk_util::SetAlwaysShowImage(menu_item);
|
| -
|
| - return AppendMenuItemToMenu(command_id, NULL, menu_item, menu_, true);
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::AppendMenuItemToMenu(int index,
|
| - menus::MenuModel* model,
|
| - GtkWidget* menu_item,
|
| - GtkWidget* menu,
|
| - bool connect_to_activate) {
|
| - SetMenuItemID(menu_item, index);
|
| -
|
| - // Native menu items do their own thing, so only selectively listen for the
|
| - // activate signal.
|
| - if (connect_to_activate) {
|
| - g_signal_connect(menu_item, "activate",
|
| - G_CALLBACK(OnMenuItemActivatedThunk), this);
|
| - }
|
| -
|
| - // AppendMenuItemToMenu is used both internally when we control menu creation
|
| - // from a model (where the model can choose to hide certain menu items), and
|
| - // with immediate commands which don't provide the option.
|
| - if (model) {
|
| - if (model->IsVisibleAt(index))
|
| - gtk_widget_show(menu_item);
|
| - } else {
|
| - gtk_widget_show(menu_item);
|
| - }
|
| - gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
|
| - return menu_item;
|
| -}
|
| -
|
| -void MenuGtk::Popup(GtkWidget* widget, GdkEvent* event) {
|
| - DCHECK(event->type == GDK_BUTTON_PRESS)
|
| - << "Non-button press event sent to RunMenuAt";
|
| -
|
| - Popup(widget, event->button.button, event->button.time);
|
| -}
|
| -
|
| -void MenuGtk::Popup(GtkWidget* widget, gint button_type, guint32 timestamp) {
|
| - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
|
| - WidgetMenuPositionFunc,
|
| - widget,
|
| - button_type, timestamp);
|
| -}
|
| -
|
| -void MenuGtk::PopupAsContext(guint32 event_time) {
|
| - // TODO(estade): |button| value of 3 (6th argument) is not strictly true,
|
| - // but does it matter?
|
| - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, NULL, NULL, 3, event_time);
|
| -}
|
| -
|
| -void MenuGtk::PopupAsContextAt(guint32 event_time, gfx::Point point) {
|
| - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL,
|
| - PointMenuPositionFunc, &point, 3, event_time);
|
| -}
|
| -
|
| -void MenuGtk::PopupAsContextForStatusIcon(guint32 event_time, guint32 button,
|
| - GtkStatusIcon* icon) {
|
| - gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, gtk_status_icon_position_menu,
|
| - icon, button, event_time);
|
| -}
|
| -
|
| -void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) {
|
| - Popup(widget, 0, gtk_get_current_event_time());
|
| - gtk_menu_shell_select_first(GTK_MENU_SHELL(menu_), FALSE);
|
| -}
|
| -
|
| -void MenuGtk::Cancel() {
|
| - gtk_menu_popdown(GTK_MENU(menu_));
|
| -}
|
| -
|
| -void MenuGtk::UpdateMenu() {
|
| - gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this);
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
|
| - GtkWidget* image) {
|
| - GtkWidget* menu_item =
|
| - gtk_image_menu_item_new_with_mnemonic(label.c_str());
|
| - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
|
| - return menu_item;
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::BuildMenuItemWithImage(const std::string& label,
|
| - const SkBitmap& icon) {
|
| - GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
|
| - GtkWidget* menu_item = BuildMenuItemWithImage(label,
|
| - gtk_image_new_from_pixbuf(pixbuf));
|
| - g_object_unref(pixbuf);
|
| - return menu_item;
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::BuildMenuItemWithLabel(const std::string& label,
|
| - int command_id) {
|
| - GtkWidget* img =
|
| - delegate_ ? delegate_->GetImageForCommandId(command_id) :
|
| - MenuGtk::Delegate::GetDefaultImageForCommandId(command_id);
|
| - return img ? BuildMenuItemWithImage(label, img) :
|
| - gtk_menu_item_new_with_mnemonic(label.c_str());
|
| -}
|
| -
|
| -void MenuGtk::BuildMenuFromModel() {
|
| - BuildSubmenuFromModel(model_, menu_);
|
| -}
|
| -
|
| -void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) {
|
| - std::map<int, GtkWidget*> radio_groups;
|
| - GtkWidget* menu_item = NULL;
|
| - for (int i = 0; i < model->GetItemCount(); ++i) {
|
| - SkBitmap icon;
|
| - std::string label =
|
| - gfx::ConvertAcceleratorsFromWindowsStyle(
|
| - UTF16ToUTF8(model->GetLabelAt(i)));
|
| - bool connect_to_activate = true;
|
| -
|
| - switch (model->GetTypeAt(i)) {
|
| - case menus::MenuModel::TYPE_SEPARATOR:
|
| - menu_item = gtk_separator_menu_item_new();
|
| - break;
|
| -
|
| - case menus::MenuModel::TYPE_CHECK:
|
| - menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
|
| - break;
|
| -
|
| - case menus::MenuModel::TYPE_RADIO: {
|
| - std::map<int, GtkWidget*>::iterator iter =
|
| - radio_groups.find(model->GetGroupIdAt(i));
|
| -
|
| - if (iter == radio_groups.end()) {
|
| - menu_item = gtk_radio_menu_item_new_with_mnemonic(
|
| - NULL, label.c_str());
|
| - radio_groups[model->GetGroupIdAt(i)] = menu_item;
|
| - } else {
|
| - menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
|
| - GTK_RADIO_MENU_ITEM(iter->second), label.c_str());
|
| - }
|
| - break;
|
| - }
|
| - case menus::MenuModel::TYPE_BUTTON_ITEM: {
|
| - menus::ButtonMenuItemModel* button_menu_item_model =
|
| - model->GetButtonMenuItemAt(i);
|
| - menu_item = BuildButtomMenuItem(button_menu_item_model, menu);
|
| - connect_to_activate = false;
|
| - break;
|
| - }
|
| - case menus::MenuModel::TYPE_SUBMENU:
|
| - case menus::MenuModel::TYPE_COMMAND: {
|
| - int command_id = model->GetCommandIdAt(i);
|
| - if (model->GetIconAt(i, &icon))
|
| - menu_item = BuildMenuItemWithImage(label, icon);
|
| - else
|
| - menu_item = BuildMenuItemWithLabel(label, command_id);
|
| - if (delegate_ && delegate_->AlwaysShowIconForCmd(command_id) &&
|
| - GTK_IS_IMAGE_MENU_ITEM(menu_item))
|
| - gtk_util::SetAlwaysShowImage(menu_item);
|
| - break;
|
| - }
|
| -
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| -
|
| - if (model->GetTypeAt(i) == menus::MenuModel::TYPE_SUBMENU) {
|
| - GtkWidget* submenu = gtk_menu_new();
|
| - BuildSubmenuFromModel(model->GetSubmenuModelAt(i), submenu);
|
| - gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
|
| - }
|
| -
|
| - menus::AcceleratorGtk accelerator;
|
| - if (model->GetAcceleratorAt(i, &accelerator)) {
|
| - gtk_widget_add_accelerator(menu_item,
|
| - "activate",
|
| - dummy_accel_group_,
|
| - accelerator.GetGdkKeyCode(),
|
| - accelerator.gdk_modifier_type(),
|
| - GTK_ACCEL_VISIBLE);
|
| - }
|
| -
|
| - g_object_set_data(G_OBJECT(menu_item), "model", model);
|
| - AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate);
|
| -
|
| - menu_item = NULL;
|
| - }
|
| -}
|
| -
|
| -GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model,
|
| - GtkWidget* menu) {
|
| - GtkWidget* menu_item = gtk_custom_menu_item_new(
|
| - gfx::RemoveWindowsStyleAccelerators(UTF16ToUTF8(model->label())).c_str());
|
| -
|
| - // Set up the callback to the model for when it is clicked.
|
| - g_object_set_data(G_OBJECT(menu_item), "button-model", model);
|
| - g_signal_connect(menu_item, "button-pushed",
|
| - G_CALLBACK(OnMenuButtonPressedThunk), this);
|
| - g_signal_connect(menu_item, "try-button-pushed",
|
| - G_CALLBACK(OnMenuTryButtonPressedThunk), this);
|
| -
|
| - GtkSizeGroup* group = NULL;
|
| - for (int i = 0; i < model->GetItemCount(); ++i) {
|
| - GtkWidget* button = NULL;
|
| -
|
| - 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: {
|
| - 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)) {
|
| - SetupImageIcon(button, menu, icon_idr, delegate_);
|
| - } else {
|
| - gtk_button_set_label(
|
| - GTK_BUTTON(button),
|
| - gfx::RemoveWindowsStyleAccelerators(
|
| - UTF16ToUTF8(model->GetLabelAt(i))).c_str());
|
| - }
|
| -
|
| - SetupButtonShowHandler(button, model, i);
|
| - break;
|
| - }
|
| - case menus::ButtonMenuItemModel::TYPE_BUTTON_LABEL: {
|
| - button = gtk_custom_menu_item_add_button_label(
|
| - GTK_CUSTOM_MENU_ITEM(menu_item),
|
| - model->GetCommandIdAt(i));
|
| - gtk_button_set_label(
|
| - GTK_BUTTON(button),
|
| - gfx::RemoveWindowsStyleAccelerators(
|
| - UTF16ToUTF8(model->GetLabelAt(i))).c_str());
|
| - SetupButtonShowHandler(button, model, i);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (button && model->PartOfGroup(i)) {
|
| - if (!group)
|
| - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
|
| -
|
| - gtk_size_group_add_widget(group, button);
|
| - }
|
| - }
|
| -
|
| - if (group) {
|
| - g_object_unref(group);
|
| - }
|
| -
|
| - return menu_item;
|
| -}
|
| -
|
| -void MenuGtk::OnMenuItemActivated(GtkWidget* menuitem) {
|
| - if (block_activation_)
|
| - return;
|
| -
|
| - // We receive activation messages when highlighting a menu that has a
|
| - // submenu. Ignore them.
|
| - if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(menuitem)))
|
| - return;
|
| -
|
| - // The activate signal is sent to radio items as they get deselected;
|
| - // ignore it in this case.
|
| - if (GTK_IS_RADIO_MENU_ITEM(menuitem) &&
|
| - !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) {
|
| - return;
|
| - }
|
| -
|
| - int id;
|
| - if (!GetMenuItemID(menuitem, &id))
|
| - return;
|
| -
|
| - menus::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(menuitem));
|
| -
|
| - // The menu item can still be activated by hotkeys even if it is disabled.
|
| - if (model->IsEnabledAt(id))
|
| - ExecuteCommand(model, id);
|
| -}
|
| -
|
| -void MenuGtk::OnMenuButtonPressed(GtkWidget* menu_item, int command_id) {
|
| - menus::ButtonMenuItemModel* model =
|
| - reinterpret_cast<menus::ButtonMenuItemModel*>(
|
| - g_object_get_data(G_OBJECT(menu_item), "button-model"));
|
| - if (model && model->IsCommandIdEnabled(command_id)) {
|
| - if (delegate_)
|
| - delegate_->CommandWillBeExecuted();
|
| -
|
| - model->ActivatedCommand(command_id);
|
| - }
|
| -}
|
| -
|
| -gboolean MenuGtk::OnMenuTryButtonPressed(GtkWidget* menu_item,
|
| - int command_id) {
|
| - gboolean pressed = FALSE;
|
| - menus::ButtonMenuItemModel* model =
|
| - reinterpret_cast<menus::ButtonMenuItemModel*>(
|
| - g_object_get_data(G_OBJECT(menu_item), "button-model"));
|
| - if (model &&
|
| - model->IsCommandIdEnabled(command_id) &&
|
| - !model->DoesCommandIdDismissMenu(command_id)) {
|
| - if (delegate_)
|
| - delegate_->CommandWillBeExecuted();
|
| -
|
| - model->ActivatedCommand(command_id);
|
| - pressed = TRUE;
|
| - }
|
| -
|
| - return pressed;
|
| -}
|
| -
|
| -// static
|
| -void MenuGtk::WidgetMenuPositionFunc(GtkMenu* menu,
|
| - int* x,
|
| - int* y,
|
| - gboolean* push_in,
|
| - void* void_widget) {
|
| - GtkWidget* widget = GTK_WIDGET(void_widget);
|
| - GtkRequisition menu_req;
|
| -
|
| - gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
|
| -
|
| - gdk_window_get_origin(widget->window, x, y);
|
| - GdkScreen *screen = gtk_widget_get_screen(widget);
|
| - gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y);
|
| -
|
| - GdkRectangle screen_rect;
|
| - gdk_screen_get_monitor_geometry(screen, monitor,
|
| - &screen_rect);
|
| -
|
| - if (GTK_WIDGET_NO_WINDOW(widget)) {
|
| - *x += widget->allocation.x;
|
| - *y += widget->allocation.y;
|
| - }
|
| - *y += widget->allocation.height;
|
| -
|
| - bool start_align =
|
| - !!g_object_get_data(G_OBJECT(widget), "left-align-popup");
|
| - if (base::i18n::IsRTL())
|
| - start_align = !start_align;
|
| -
|
| - if (!start_align)
|
| - *x += widget->allocation.width - menu_req.width;
|
| -
|
| - *y = CalculateMenuYPosition(&screen_rect, &menu_req, widget, *y);
|
| -
|
| - *push_in = FALSE;
|
| -}
|
| -
|
| -// static
|
| -void MenuGtk::PointMenuPositionFunc(GtkMenu* menu,
|
| - int* x,
|
| - int* y,
|
| - gboolean* push_in,
|
| - gpointer userdata) {
|
| - *push_in = TRUE;
|
| -
|
| - gfx::Point* point = reinterpret_cast<gfx::Point*>(userdata);
|
| - *x = point->x();
|
| - *y = point->y();
|
| -
|
| - GtkRequisition menu_req;
|
| - gtk_widget_size_request(GTK_WIDGET(menu), &menu_req);
|
| - GdkScreen* screen;
|
| - gdk_display_get_pointer(gdk_display_get_default(), &screen, NULL, NULL, NULL);
|
| - gint monitor = gdk_screen_get_monitor_at_point(screen, *x, *y);
|
| -
|
| - GdkRectangle screen_rect;
|
| - gdk_screen_get_monitor_geometry(screen, monitor, &screen_rect);
|
| -
|
| - *y = CalculateMenuYPosition(&screen_rect, &menu_req, NULL, *y);
|
| -}
|
| -
|
| -void MenuGtk::ExecuteCommand(menus::MenuModel* model, int id) {
|
| - if (delegate_)
|
| - delegate_->CommandWillBeExecuted();
|
| -
|
| - GdkEvent* event = gtk_get_current_event();
|
| - if (event && event->type == GDK_BUTTON_RELEASE) {
|
| - model->ActivatedAtWithDisposition(
|
| - id, event_utils::DispositionFromEventFlags(event->button.state));
|
| - } else {
|
| - model->ActivatedAt(id);
|
| - }
|
| -
|
| - if (event)
|
| - gdk_event_free(event);
|
| -}
|
| -
|
| -void MenuGtk::OnMenuShow(GtkWidget* widget) {
|
| - MessageLoop::current()->PostTask(FROM_HERE,
|
| - factory_.NewRunnableMethod(&MenuGtk::UpdateMenu));
|
| -}
|
| -
|
| -void MenuGtk::OnMenuHidden(GtkWidget* widget) {
|
| - if (delegate_)
|
| - delegate_->StoppedShowing();
|
| -}
|
| -
|
| -// static
|
| -void MenuGtk::SetButtonItemInfo(GtkWidget* button, gpointer userdata) {
|
| - menus::ButtonMenuItemModel* model =
|
| - reinterpret_cast<menus::ButtonMenuItemModel*>(
|
| - g_object_get_data(G_OBJECT(button), "button-model"));
|
| - int index = GPOINTER_TO_INT(g_object_get_data(
|
| - G_OBJECT(button), "button-model-id"));
|
| -
|
| - if (model->IsItemDynamicAt(index)) {
|
| - std::string label =
|
| - gfx::ConvertAcceleratorsFromWindowsStyle(
|
| - UTF16ToUTF8(model->GetLabelAt(index)));
|
| - gtk_button_set_label(GTK_BUTTON(button), label.c_str());
|
| - }
|
| -
|
| - gtk_widget_set_sensitive(GTK_WIDGET(button), model->IsEnabledAt(index));
|
| -}
|
| -
|
| -// static
|
| -void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) {
|
| - if (GTK_IS_SEPARATOR_MENU_ITEM(widget)) {
|
| - // We need to explicitly handle this case because otherwise we'll ask the
|
| - // menu delegate about something with an invalid id.
|
| - return;
|
| - }
|
| -
|
| - int id;
|
| - if (!GetMenuItemID(widget, &id))
|
| - return;
|
| -
|
| - menus::MenuModel* model = ModelForMenuItem(GTK_MENU_ITEM(widget));
|
| - if (!model) {
|
| - // If we're not providing the sub menu, then there's no model. For
|
| - // example, the IME submenu doesn't have a model.
|
| - return;
|
| - }
|
| -
|
| - if (GTK_IS_CHECK_MENU_ITEM(widget)) {
|
| - GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(widget);
|
| -
|
| - // gtk_check_menu_item_set_active() will send the activate signal. Touching
|
| - // the underlying "active" property will also call the "activate" handler
|
| - // for this menu item. So we prevent the "activate" handler from
|
| - // being called while we set the checkbox.
|
| - // Why not use one of the glib signal-blocking functions? Because when we
|
| - // toggle a radio button, it will deactivate one of the other radio buttons,
|
| - // which we don't have a pointer to.
|
| - // Wny not make this a member variable? Because "menu" is a pointer to the
|
| - // root of the MenuGtk and we want to disable *all* MenuGtks, including
|
| - // submenus.
|
| - block_activation_ = true;
|
| - gtk_check_menu_item_set_active(item, model->IsItemCheckedAt(id));
|
| - block_activation_ = false;
|
| - }
|
| -
|
| - if (GTK_IS_CUSTOM_MENU_ITEM(widget)) {
|
| - // Iterate across all the buttons to update their visible properties.
|
| - gtk_custom_menu_item_foreach_button(GTK_CUSTOM_MENU_ITEM(widget),
|
| - SetButtonItemInfo,
|
| - userdata);
|
| - }
|
| -
|
| - if (GTK_IS_MENU_ITEM(widget)) {
|
| - gtk_widget_set_sensitive(widget, model->IsEnabledAt(id));
|
| -
|
| - if (model->IsVisibleAt(id)) {
|
| - // Update the menu item label if it is dynamic.
|
| - if (model->IsItemDynamicAt(id)) {
|
| - std::string label =
|
| - gfx::ConvertAcceleratorsFromWindowsStyle(
|
| - UTF16ToUTF8(model->GetLabelAt(id)));
|
| -
|
| -#if GTK_CHECK_VERSION(2, 16, 0)
|
| - gtk_menu_item_set_label(GTK_MENU_ITEM(widget), label.c_str());
|
| -#else
|
| - gtk_label_set_label(GTK_LABEL(GTK_BIN(widget)->child), label.c_str());
|
| -#endif
|
| - if (GTK_IS_IMAGE_MENU_ITEM(widget)) {
|
| - SkBitmap icon;
|
| - if (model->GetIconAt(id, &icon)) {
|
| - GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
|
| - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget),
|
| - gtk_image_new_from_pixbuf(pixbuf));
|
| - g_object_unref(pixbuf);
|
| - } else {
|
| - gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL);
|
| - }
|
| - }
|
| - }
|
| -
|
| - gtk_widget_show(widget);
|
| - } else {
|
| - gtk_widget_hide(widget);
|
| - }
|
| -
|
| - GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget));
|
| - if (submenu) {
|
| - gtk_container_foreach(GTK_CONTAINER(submenu), &SetMenuItemInfo,
|
| - userdata);
|
| - }
|
| - }
|
| -}
|
|
|