diff options
-rw-r--r-- | app/menus/button_menu_item_model.cc | 20 | ||||
-rw-r--r-- | app/menus/button_menu_item_model.h | 9 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.cc | 6 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_custom_menu.cc | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_custom_menu_item.cc | 42 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_custom_menu_item.h | 13 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.cc | 120 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.h | 16 | ||||
-rw-r--r-- | chrome/browser/wrench_menu_model.cc | 10 | ||||
-rw-r--r-- | chrome/browser/wrench_menu_model.h | 7 |
10 files changed, 193 insertions, 58 deletions
diff --git a/app/menus/button_menu_item_model.cc b/app/menus/button_menu_item_model.cc index 3e09253..a7fbcde 100644 --- a/app/menus/button_menu_item_model.cc +++ b/app/menus/button_menu_item_model.cc @@ -18,6 +18,15 @@ string16 ButtonMenuItemModel::Delegate::GetLabelForCommandId( return string16(); } +bool ButtonMenuItemModel::Delegate::IsCommandIdEnabled(int command_id) const { + return true; +} + +bool ButtonMenuItemModel::Delegate::DoesCommandIdDismissMenu( + int command_id) const { + return true; +} + struct ButtonMenuItemModel::Item { int command_id; ButtonType type; @@ -106,10 +115,21 @@ bool ButtonMenuItemModel::IsEnabledAt(int index) const { return IsCommandIdEnabled(items_[index].command_id); } +bool ButtonMenuItemModel::DismissesMenuAt(int index) const { + return DoesCommandIdDismissMenu(items_[index].command_id); +} + bool ButtonMenuItemModel::IsCommandIdEnabled(int command_id) const { if (delegate_) return delegate_->IsCommandIdEnabled(command_id); return true; } +bool ButtonMenuItemModel::DoesCommandIdDismissMenu(int command_id) const { + if (delegate_) + return delegate_->DoesCommandIdDismissMenu(command_id); + return true; +} + + } // namespace menus diff --git a/app/menus/button_menu_item_model.h b/app/menus/button_menu_item_model.h index 606e286..265359b 100644 --- a/app/menus/button_menu_item_model.h +++ b/app/menus/button_menu_item_model.h @@ -31,7 +31,8 @@ class ButtonMenuItemModel { // Performs the action associated with the specified command id. virtual void ExecuteCommand(int command_id) = 0; - virtual bool IsCommandIdEnabled(int command_id) const { return true; } + virtual bool IsCommandIdEnabled(int command_id) const; + virtual bool DoesCommandIdDismissMenu(int command_id) const; protected: virtual ~Delegate() {} @@ -84,9 +85,15 @@ class ButtonMenuItemModel { // Returns the enabled state of the button at |index|. bool IsEnabledAt(int index) const; + // Returns whether clicking on the button at |index| dismisses the menu. + bool DismissesMenuAt(int index) const; + // Returns the enabled state of the command specified by |command_id|. bool IsCommandIdEnabled(int command_id) const; + // Returns whether clicking on |command_id| dismisses the menu. + bool DoesCommandIdDismissMenu(int command_id) const; + const string16& label() const { return item_label_; } private: diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc index 69fdcb6..8da933d 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_gtk.cc @@ -230,6 +230,8 @@ void BrowserToolbarGtk::Init(Profile* profile, wrench_menu_.reset(new MenuGtk(this, &wrench_menu_model_)); g_signal_connect(wrench_menu_->widget(), "show", G_CALLBACK(OnWrenchMenuShowThunk), this); + registrar_.Add(this, NotificationType::ZOOM_LEVEL_CHANGED, + Source<Profile>(browser_->profile())); if (ShouldOnlyShowLocation()) { gtk_widget_show(event_box_); @@ -379,6 +381,10 @@ void BrowserToolbarGtk::Observe(NotificationType type, UpdateRoundedness(); } else if (type == NotificationType::UPGRADE_RECOMMENDED) { MaybeShowUpgradeReminder(); + } else if (type == NotificationType::ZOOM_LEVEL_CHANGED) { + // If our zoom level changed, we need to tell the menu to update its state, + // since the menu could still be open. + wrench_menu_->UpdateMenu(); } else { NOTREACHED(); } diff --git a/chrome/browser/gtk/gtk_custom_menu.cc b/chrome/browser/gtk/gtk_custom_menu.cc index d666091..15eeb5a 100644 --- a/chrome/browser/gtk/gtk_custom_menu.cc +++ b/chrome/browser/gtk/gtk_custom_menu.cc @@ -60,7 +60,8 @@ static gboolean gtk_custom_menu_button_press(GtkWidget* widget, } // When processing a button event, abort processing if the cursor isn't in a -// clickable region. +// clickable region. If it's in a button that doesn't dismiss the menu, fire +// that event and abort having the normal GtkMenu code run. static gboolean gtk_custom_menu_button_release(GtkWidget* widget, GdkEventButton* event) { GtkWidget* menu_item = gtk_menu_shell_get_item( @@ -71,6 +72,11 @@ static gboolean gtk_custom_menu_button_release(GtkWidget* widget, // Stop processing this event. This isn't a clickable region. return TRUE; } + + if (gtk_custom_menu_item_try_no_dismiss_command( + GTK_CUSTOM_MENU_ITEM(menu_item))) { + return TRUE; + } } return GTK_WIDGET_CLASS(gtk_custom_menu_parent_class)-> diff --git a/chrome/browser/gtk/gtk_custom_menu_item.cc b/chrome/browser/gtk/gtk_custom_menu_item.cc index 55281c1..a3d62d4 100644 --- a/chrome/browser/gtk/gtk_custom_menu_item.cc +++ b/chrome/browser/gtk/gtk_custom_menu_item.cc @@ -9,6 +9,7 @@ enum { BUTTON_PUSHED, + TRY_BUTTON_PUSHED, LAST_SIGNAL }; @@ -102,6 +103,16 @@ static void gtk_custom_menu_item_class_init(GtkCustomMenuItemClass* klass) { NULL, NULL, gtk_marshal_NONE__INT, G_TYPE_NONE, 1, GTK_TYPE_INT); + // TODO(erg): Change from BOOL__POINTER to BOOLEAN__INTEGER when we get to + // use a modern GTK+. + custom_menu_item_signals[TRY_BUTTON_PUSHED] = + g_signal_new("try-button-pushed", + G_OBJECT_CLASS_TYPE(gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + gtk_marshal_BOOL__POINTER, + G_TYPE_BOOLEAN, 1, GTK_TYPE_INT); } static void gtk_custom_menu_item_finalize(GObject *object) { @@ -390,3 +401,34 @@ gboolean gtk_custom_menu_item_is_in_clickable_region( GtkCustomMenuItem* menu_item) { return menu_item->currently_selected_button != NULL; } + +gboolean gtk_custom_menu_item_try_no_dismiss_command( + GtkCustomMenuItem* menu_item) { + GtkCustomMenuItem* custom_item = GTK_CUSTOM_MENU_ITEM(menu_item); + gboolean activated = TRUE; + + // We work with |currently_selected_button| instead of + // |previously_selected_button| since we haven't been "deselect"ed yet. + gpointer id_ptr = g_object_get_data( + G_OBJECT(custom_item->currently_selected_button), "command-id"); + if (id_ptr != NULL) { + int command_id = GPOINTER_TO_INT(id_ptr); + g_signal_emit(custom_item, custom_menu_item_signals[TRY_BUTTON_PUSHED], 0, + command_id, &activated); + } + + return activated; +} + +void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item, + GtkCallback callback, + gpointer callback_data) { + // Even though we're filtering |all_widgets| on GTK_IS_BUTTON(), this isn't + // equivalent to |button_widgets| because we also want the button-labels. + for (GList* i = menu_item->all_widgets; i && GTK_IS_BUTTON(i->data); + i = g_list_next(i)) { + if (GTK_IS_BUTTON(i->data)) { + callback(GTK_WIDGET(i->data), callback_data); + } + } +} diff --git a/chrome/browser/gtk/gtk_custom_menu_item.h b/chrome/browser/gtk/gtk_custom_menu_item.h index c730342..76e8c9a 100644 --- a/chrome/browser/gtk/gtk_custom_menu_item.h +++ b/chrome/browser/gtk/gtk_custom_menu_item.h @@ -123,6 +123,19 @@ void gtk_custom_menu_item_select_item_by_direction( gboolean gtk_custom_menu_item_is_in_clickable_region( GtkCustomMenuItem* menu_item); +// If the button is released while the |currently_selected_button| isn't +// supposed to dismiss the menu, this signals to our listeners that we want to +// run this command if it doesn't dismiss the menu. Returns TRUE if we acted +// on this button click (and should prevent the normal GtkMenu machinery from +// firing an "activate" signal). +gboolean gtk_custom_menu_item_try_no_dismiss_command( + GtkCustomMenuItem* menu_item); + +// Calls |callback| with every button and button-label in the container. +void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem* menu_item, + GtkCallback callback, + gpointer callback_data); + G_END_DECLS #endif // CHROME_BROWSER_GTK_GTK_CUSTOM_MENU_ITEM_H_ diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc index f242450..4d58ae1 100644 --- a/chrome/browser/gtk/menu_gtk.cc +++ b/chrome/browser/gtk/menu_gtk.cc @@ -54,49 +54,13 @@ menus::MenuModel* ModelForMenuItem(GtkMenuItem* menu_item) { g_object_get_data(G_OBJECT(menu_item), "model")); } -void OnSubmenuShow(GtkWidget* widget, gpointer user_data) { - gint index = GPOINTER_TO_INT(user_data); - - GtkMenuItem* item = - GTK_MENU_ITEM(g_list_nth(GTK_MENU_SHELL(widget)->children, index)->data); - menus::MenuModel* model = ModelForMenuItem(item); - std::string label = - ConvertAcceleratorsFromWindowsStyle( - UTF16ToUTF8(model->GetLabelAt(index))); - -#if GTK_CHECK_VERSION(2, 16, 0) - gtk_menu_item_set_label(item, label.c_str()); -#else - gtk_label_set_label(GTK_LABEL(GTK_BIN(item)->child), label.c_str()); -#endif -} - -void OnSubmenuShowButtonMenuItem(GtkWidget* widget, GtkButton* button) { - 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->IsLabelDynamicAt(index)) { - std::string label = - 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)); -} - void SetupButtonShowHandler(GtkWidget* button, - GtkWidget* menu, 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)); - g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShowButtonMenuItem), - button); } void OnSubmenuShowButtonImage(GtkWidget* widget, GtkButton* button) { @@ -222,10 +186,11 @@ GtkWidget* MenuGtk::AppendMenuItemToMenu(int index, 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) { - SetMenuItemID(menu_item, index); g_signal_connect(menu_item, "activate", G_CALLBACK(OnMenuItemActivatedThunk), this); } @@ -283,6 +248,10 @@ 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, const SkBitmap& icon) { GtkWidget* menu_item = @@ -372,11 +341,6 @@ void MenuGtk::BuildSubmenuFromModel(menus::MenuModel* model, GtkWidget* menu) { g_object_set_data(G_OBJECT(menu_item), "model", model); AppendMenuItemToMenu(i, model, menu_item, menu, connect_to_activate); - if (model->IsLabelDynamicAt(i)) { - g_signal_connect(menu, "show", G_CALLBACK(OnSubmenuShow), - GINT_TO_POINTER(i)); - } - menu_item = NULL; } } @@ -390,6 +354,8 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model, 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) { @@ -415,7 +381,7 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model, UTF16ToUTF8(model->GetLabelAt(i))).c_str()); } - SetupButtonShowHandler(button, menu, model, i); + SetupButtonShowHandler(button, model, i); break; } case menus::ButtonMenuItemModel::TYPE_BUTTON_LABEL: { @@ -426,7 +392,7 @@ GtkWidget* MenuGtk::BuildButtomMenuItem(menus::ButtonMenuItemModel* model, GTK_BUTTON(button), RemoveWindowsStyleAccelerators( UTF16ToUTF8(model->GetLabelAt(i))).c_str()); - SetupButtonShowHandler(button, menu, model, i); + SetupButtonShowHandler(button, model, i); break; } } @@ -485,6 +451,25 @@ void MenuGtk::OnMenuButtonPressed(GtkWidget* menu_item, int 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, @@ -547,10 +532,6 @@ void MenuGtk::PointMenuPositionFunc(GtkMenu* menu, *y = CalculateMenuYPosition(&screen_rect, &menu_req, NULL, *y); } -void MenuGtk::UpdateMenu() { - gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this); -} - void MenuGtk::ExecuteCommand(menus::MenuModel* model, int id) { if (delegate_) delegate_->CommandWillBeExecuted(); @@ -569,6 +550,24 @@ void MenuGtk::OnMenuHidden(GtkWidget* widget) { } // 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->IsLabelDynamicAt(index)) { + std::string label = + 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 @@ -605,13 +604,34 @@ void MenuGtk::SetMenuItemInfo(GtkWidget* widget, gpointer userdata) { 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)) + if (model->IsVisibleAt(id)) { + // Update the menu item label if it is dynamic. + if (model->IsLabelDynamicAt(id)) { + std::string label = + 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 + } + gtk_widget_show(widget); - else + } else { gtk_widget_hide(widget); + } GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(widget)); if (submenu) { diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h index 562211d..b4bc98c 100644 --- a/chrome/browser/gtk/menu_gtk.h +++ b/chrome/browser/gtk/menu_gtk.h @@ -117,6 +117,9 @@ class MenuGtk { GtkWidget* widget() const { return menu_; } + // Updates all the enabled/checked states and the dynamic labels. + void UpdateMenu(); + private: // Builds a GtkImageMenuItem. GtkWidget* BuildMenuItemWithImage(const std::string& label, @@ -130,9 +133,6 @@ class MenuGtk { GtkWidget* BuildButtomMenuItem(menus::ButtonMenuItemModel* model, GtkWidget* menu); - // Contains implementation for OnMenuShow. - void UpdateMenu(); - void ExecuteCommand(menus::MenuModel* model, int id); // Callback for when a menu item is clicked. @@ -141,13 +141,21 @@ class MenuGtk { // Called when one of the buttons are pressed. CHROMEGTK_CALLBACK_1(MenuGtk, void, OnMenuButtonPressed, int); + // Called to maybe activate a button if that button isn't supposed to dismiss + // the menu. + CHROMEGTK_CALLBACK_1(MenuGtk, gboolean, OnMenuTryButtonPressed, int); + // Updates all the menu items' state. CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuShow); // Sets the activating widget back to a normal appearance. CHROMEGTK_CALLBACK_0(MenuGtk, void, OnMenuHidden); - // Sets the check mark and enabled/disabled state on our menu items. + // Sets the enable/disabled state and dynamic labels on our menu items. + static void SetButtonItemInfo(GtkWidget* button, gpointer userdata); + + // Sets the check mark, enabled/disabled state and dynamic labels on our menu + // items. static void SetMenuItemInfo(GtkWidget* widget, void* raw_menu); // Queries this object about the menu state. diff --git a/chrome/browser/wrench_menu_model.cc b/chrome/browser/wrench_menu_model.cc index bd8b0ac..3273eaf 100644 --- a/chrome/browser/wrench_menu_model.cc +++ b/chrome/browser/wrench_menu_model.cc @@ -54,6 +54,9 @@ EncodingMenuModel::EncodingMenuModel(Browser* browser) Build(); } +EncodingMenuModel::~EncodingMenuModel() { +} + void EncodingMenuModel::Build() { EncodingMenuController::EncodingMenuItemList encoding_menu_items; EncodingMenuController encoding_menu_controller; @@ -119,6 +122,9 @@ ZoomMenuModel::ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate) Build(); } +ZoomMenuModel::~ZoomMenuModel() { +} + void ZoomMenuModel::Build() { AddItemWithStringId(IDC_ZOOM_PLUS, IDS_ZOOM_PLUS); AddItemWithStringId(IDC_ZOOM_NORMAL, IDS_ZOOM_NORMAL); @@ -193,6 +199,10 @@ WrenchMenuModel::~WrenchMenuModel() { tabstrip_model_->RemoveObserver(this); } +bool WrenchMenuModel::DoesCommandIdDismissMenu(int command_id) const { + return command_id != IDC_ZOOM_MINUS && command_id != IDC_ZOOM_PLUS; +} + bool WrenchMenuModel::IsLabelForCommandIdDynamic(int command_id) const { return command_id == IDC_ZOOM_PERCENT_DISPLAY || #if defined(OS_MACOSX) diff --git a/chrome/browser/wrench_menu_model.h b/chrome/browser/wrench_menu_model.h index 6f40fde..8011be1 100644 --- a/chrome/browser/wrench_menu_model.h +++ b/chrome/browser/wrench_menu_model.h @@ -26,7 +26,7 @@ class EncodingMenuModel : public menus::SimpleMenuModel, public menus::SimpleMenuModel::Delegate { public: explicit EncodingMenuModel(Browser* browser); - virtual ~EncodingMenuModel() {} + virtual ~EncodingMenuModel(); // Overridden from menus::SimpleMenuModel::Delegate: virtual bool IsCommandIdChecked(int command_id) const; @@ -47,7 +47,7 @@ class EncodingMenuModel : public menus::SimpleMenuModel, class ZoomMenuModel : public menus::SimpleMenuModel { public: explicit ZoomMenuModel(menus::SimpleMenuModel::Delegate* delegate); - virtual ~ZoomMenuModel() {} + virtual ~ZoomMenuModel(); private: void Build(); @@ -78,6 +78,9 @@ class WrenchMenuModel : public menus::SimpleMenuModel, WrenchMenuModel(menus::AcceleratorProvider* provider, Browser* browser); virtual ~WrenchMenuModel(); + // Overridden for ButtonMenuItemModel::Delegate: + virtual bool DoesCommandIdDismissMenu(int command_id) const; + // Overridden for both ButtonMenuItemModel::Delegate and SimpleMenuModel: virtual bool IsLabelForCommandIdDynamic(int command_id) const; virtual string16 GetLabelForCommandId(int command_id) const; |