diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-18 22:30:16 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-18 22:30:16 +0000 |
commit | 70b45efc15674aa7241bbb95dc81b3019eac294b (patch) | |
tree | b4b8cae88b43ffb0a669cc7b50aabafa93506a02 /chrome/browser/gtk | |
parent | cb71491f6fd9eb062ecbce3df5ca543c77652d91 (diff) | |
download | chromium_src-70b45efc15674aa7241bbb95dc81b3019eac294b.zip chromium_src-70b45efc15674aa7241bbb95dc81b3019eac294b.tar.gz chromium_src-70b45efc15674aa7241bbb95dc81b3019eac294b.tar.bz2 |
Port back_forward_menu_model to linux.
* Refactor BackForwardMenuModel.
- Create platform-specific subclasses that implement menu delegate interfaces
- Push almost all functionality into BackForwardMenuModel
* Implement GTK back/forward dropdowns (in MenuGtk and BrowserToolbarViewGtk)
Review URL: http://codereview.chromium.org/21440
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9983 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/back_forward_menu_model_gtk.cc | 47 | ||||
-rw-r--r-- | chrome/browser/gtk/back_forward_menu_model_gtk.h | 34 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_view_gtk.cc | 92 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_view_gtk.h | 43 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.cc | 68 | ||||
-rw-r--r-- | chrome/browser/gtk/menu_gtk.h | 40 |
6 files changed, 290 insertions, 34 deletions
diff --git a/chrome/browser/gtk/back_forward_menu_model_gtk.cc b/chrome/browser/gtk/back_forward_menu_model_gtk.cc new file mode 100644 index 0000000..6db3234 --- /dev/null +++ b/chrome/browser/gtk/back_forward_menu_model_gtk.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2009 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/back_forward_menu_model_gtk.h" + +#include "base/string_util.h" + +// static +BackForwardMenuModel* BackForwardMenuModel::Create(Browser* browser, + ModelType model_type) { + return new BackForwardMenuModelGtk(browser, model_type); +} + +BackForwardMenuModelGtk::BackForwardMenuModelGtk(Browser* browser, + ModelType model_type) { + browser_ = browser; + model_type_ = model_type; +} + +int BackForwardMenuModelGtk::GetItemCount() const { + return GetTotalItemCount(); +} + +bool BackForwardMenuModelGtk::IsItemSeparator(int command_id) const { + return IsSeparator(command_id); +} + +std::string BackForwardMenuModelGtk::GetLabel(int command_id) const { + return WideToUTF8(GetItemLabel(command_id)); +} + +bool BackForwardMenuModelGtk::HasIcon(int command_id) const { + return ItemHasIcon(command_id); +} + +const SkBitmap* BackForwardMenuModelGtk::GetIcon(int command_id) const { + return &GetItemIcon(command_id); +} + +bool BackForwardMenuModelGtk::IsCommandEnabled(int command_id) const { + return ItemHasCommand(command_id); +} + +void BackForwardMenuModelGtk::ExecuteCommand(int command_id) { + ExecuteCommandById(command_id); +} diff --git a/chrome/browser/gtk/back_forward_menu_model_gtk.h b/chrome/browser/gtk/back_forward_menu_model_gtk.h new file mode 100644 index 0000000..59ff869 --- /dev/null +++ b/chrome/browser/gtk/back_forward_menu_model_gtk.h @@ -0,0 +1,34 @@ +// Copyright (c) 2009 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. + +#ifndef CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_GTK_H_ +#define CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_GTK_H_ + +#include "base/basictypes.h" + +#include "chrome/browser/back_forward_menu_model.h" +#include "chrome/browser/gtk/menu_gtk.h" + +// For the most part, this class simply passes calls through to +// the BackForwardMenuModel. +class BackForwardMenuModelGtk : public BackForwardMenuModel, + public MenuGtk::Delegate { + public: + BackForwardMenuModelGtk(Browser* browser, ModelType model_type); + + // MenuGtk::Delegate + virtual int GetItemCount() const; + virtual bool IsItemSeparator(int menu_id) const; + virtual std::string GetLabel(int menu_id) const; + virtual bool HasIcon(int menu_id) const; + virtual const SkBitmap* GetIcon(int menu_id) const; + virtual bool IsCommandEnabled(int command_id) const; + virtual void ExecuteCommand(int command_id); + + private: + DISALLOW_COPY_AND_ASSIGN(BackForwardMenuModelGtk); +}; + +#endif // CHROME_BROWSER_BACK_FORWARD_MENU_MODEL_GTK_H_ + diff --git a/chrome/browser/gtk/browser_toolbar_view_gtk.cc b/chrome/browser/gtk/browser_toolbar_view_gtk.cc index b2ba34b..4188803 100644 --- a/chrome/browser/gtk/browser_toolbar_view_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_view_gtk.cc @@ -9,6 +9,7 @@ #include "base/path_service.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/browser.h" +#include "chrome/browser/gtk/back_forward_menu_model_gtk.h" #include "chrome/browser/gtk/menu_gtk.h" #include "chrome/browser/gtk/standard_menus.h" #include "chrome/common/l10n_util.h" @@ -19,6 +20,9 @@ #include "grit/theme_resources.h" const int BrowserToolbarGtk::kToolbarHeight = 38; +// For the back/forward dropdown menus, the time in milliseconds between +// when the user clicks and the popup menu appears. +static const int kMenuTimerDelay = 500; // CustomDrawButton manages the lifetimes of some resources used to make a // custom-drawn Gtk button. We use them on the toolbar. @@ -133,18 +137,18 @@ BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser) entry_(NULL), model_(browser->toolbar_model()), browser_(browser), - profile_(NULL) { + profile_(NULL), + show_menu_factory_(this) { browser_->command_updater()->AddCommandObserver(IDC_BACK, this); browser_->command_updater()->AddCommandObserver(IDC_FORWARD, this); browser_->command_updater()->AddCommandObserver(IDC_RELOAD, this); browser_->command_updater()->AddCommandObserver(IDC_HOME, this); browser_->command_updater()->AddCommandObserver(IDC_STAR, this); - // TODO(port): Port BackForwardMenuModel - // back_menu_model_.reset(new BackForwardMenuModel( - // browser, BackForwardMenuModel::BACKWARD_MENU_DELEGATE)); - // forward_menu_model_.reset(new BackForwardMenuModel( - // browser, BackForwardMenuModel::FORWARD_MENU_DELEGATE)); + back_menu_model_.reset(new BackForwardMenuModelGtk( + browser, BackForwardMenuModel::BACKWARD_MENU_DELEGATE)); + forward_menu_model_.reset(new BackForwardMenuModelGtk( + browser, BackForwardMenuModel::FORWARD_MENU_DELEGATE)); } BrowserToolbarGtk::~BrowserToolbarGtk() { @@ -160,10 +164,12 @@ void BrowserToolbarGtk::Init(Profile* profile) { toolbar_tooltips_ = gtk_tooltips_new(); - back_.reset(BuildToolbarButton(IDR_BACK, IDR_BACK_P, IDR_BACK_H, IDR_BACK_D, - l10n_util::GetString(IDS_TOOLTIP_BACK), false)); - forward_.reset(BuildToolbarButton(IDR_FORWARD, IDR_FORWARD_P, IDR_FORWARD_H, - IDR_FORWARD_D, l10n_util::GetString(IDS_TOOLTIP_FORWARD), false)); + back_.reset(BuildBackForwardButton(IDR_BACK, IDR_BACK_P, IDR_BACK_H, + IDR_BACK_D, + l10n_util::GetString(IDS_TOOLTIP_BACK))); + forward_.reset(BuildBackForwardButton(IDR_FORWARD, IDR_FORWARD_P, + IDR_FORWARD_H, IDR_FORWARD_D, + l10n_util::GetString(IDS_TOOLTIP_FORWARD))); gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0); @@ -273,7 +279,7 @@ BrowserToolbarGtk::CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton( WideToUTF8(localized_tooltip).c_str(), WideToUTF8(localized_tooltip).c_str()); if (menu_button) { - g_signal_connect(G_OBJECT(button->widget()), "button_press_event", + g_signal_connect(G_OBJECT(button->widget()), "button-press-event", G_CALLBACK(OnMenuButtonPressEvent), this); } else { g_signal_connect(G_OBJECT(button->widget()), "clicked", @@ -284,7 +290,7 @@ BrowserToolbarGtk::CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton( return button; } -/* static */ +// static void BrowserToolbarGtk::OnEntryActivate(GtkEntry *entry, BrowserToolbarGtk* toolbar) { GURL dest(std::string(gtk_entry_get_text(entry))); @@ -310,14 +316,17 @@ void BrowserToolbarGtk::OnButtonClick(GtkWidget* button, else if (button == toolbar->star_->widget()) tag = IDC_STAR; + if (tag == IDC_BACK || tag == IDC_FORWARD) + toolbar->show_menu_factory_.RevokeAll(); + DCHECK(tag != -1) << "Impossible button click callback"; toolbar->browser_->ExecuteCommand(tag); } -/* static */ -gint BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button, - GdkEvent* event, - BrowserToolbarGtk* toolbar) { +// static +gboolean BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button, + GdkEvent* event, + BrowserToolbarGtk* toolbar) { if (event->type == GDK_BUTTON_PRESS) { GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event); if (event_button->button == 1) { @@ -335,6 +344,57 @@ gint BrowserToolbarGtk::OnMenuButtonPressEvent(GtkWidget* button, return FALSE; } +BrowserToolbarGtk::CustomDrawButton* BrowserToolbarGtk::BuildBackForwardButton( + int normal_id, + int active_id, + int highlight_id, + int depressed_id, + const std::wstring& localized_tooltip) { + CustomDrawButton* button = new CustomDrawButton(normal_id, active_id, + highlight_id, depressed_id); + + // TODO(erg): Mismatch between wstring and string. + // gtk_tooltips_set_tip(GTK_TOOLTIPS(toolbar_tooltips_), + // GTK_WIDGET(back_), + // localized_tooltip, localized_tooltip); + + g_signal_connect(G_OBJECT(button->widget()), "button-press-event", + G_CALLBACK(OnBackForwardPressEvent), this); + g_signal_connect(G_OBJECT(button->widget()), "clicked", + G_CALLBACK(OnButtonClick), this); + + gtk_box_pack_start(GTK_BOX(toolbar_), button->widget(), FALSE, FALSE, 0); + // Popup the menu as left-aligned relative to this widget rather than the + // default of right aligned. + g_object_set_data(G_OBJECT(button->widget()), "left-align-popup", + reinterpret_cast<void*>(true)); + return button; +} + +// static +gboolean BrowserToolbarGtk::OnBackForwardPressEvent(GtkWidget* widget, + GdkEventButton* event, + BrowserToolbarGtk* toolbar) { + // TODO(port): only allow left clicks to open the menu. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + toolbar->show_menu_factory_.NewRunnableMethod( + &BrowserToolbarGtk::ShowBackForwardMenu, + widget, event->button), + kMenuTimerDelay); + return FALSE; +} + +void BrowserToolbarGtk::ShowBackForwardMenu(GtkWidget* widget, + gint button_type) { + if (widget == back_->widget()) { + back_forward_menu_.reset(new MenuGtk(back_menu_model_.get())); + } else { + back_forward_menu_.reset(new MenuGtk(forward_menu_model_.get())); + } + + back_forward_menu_->Popup(widget, button_type, gtk_get_current_event_time()); +} + void BrowserToolbarGtk::RunPageMenu(GdkEvent* button_press_event) { if (page_menu_ == NULL) { page_menu_.reset(new MenuGtk(this, GetStandardPageMenu())); diff --git a/chrome/browser/gtk/browser_toolbar_view_gtk.h b/chrome/browser/gtk/browser_toolbar_view_gtk.h index e98097a..c000e9b 100644 --- a/chrome/browser/gtk/browser_toolbar_view_gtk.h +++ b/chrome/browser/gtk/browser_toolbar_view_gtk.h @@ -9,10 +9,12 @@ #include <string> #include "base/scoped_ptr.h" +#include "base/task.h" #include "chrome/browser/command_updater.h" #include "chrome/browser/gtk/menu_gtk.h" #include "chrome/common/pref_member.h" +class BackForwardMenuModelGtk; class Browser; class Profile; class TabContents; @@ -67,9 +69,9 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, static void OnButtonClick(GtkWidget* button, BrowserToolbarGtk* toolbar); // Gtk callback to intercept mouse clicks to the menu buttons. - static gint OnMenuButtonPressEvent(GtkWidget* button, - GdkEvent *event, - BrowserToolbarGtk* toolbar); + static gboolean OnMenuButtonPressEvent(GtkWidget* button, + GdkEvent *event, + BrowserToolbarGtk* toolbar); // Displays the page menu. void RunPageMenu(GdkEvent* button_press_event); @@ -99,15 +101,42 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, scoped_ptr<MenuGtk> page_menu_; scoped_ptr<MenuGtk> app_menu_; - // TODO(port): Port BackForwardMenuModel - // scoped_ptr<BackForwardMenuModel> back_menu_model_; - // scoped_ptr<BackForwardMenuModel> forward_menu_model_; - Browser* browser_; Profile* profile_; // Controls whether or not a home button should be shown on the toolbar. BooleanPrefMember show_home_button_; + + // Back/Forward menus ------------------------------------------------------ + // When clicked, these buttons will navigate forward or backward. When + // pressed and held, they show a dropdown menu of recent web sites. + // TODO(port): to match windows, we need to immediately show the back/forward + // menu when the user starts dragging the mouse. + + // Builds a toolbar button for the back or forward dropdown menus. + CustomDrawButton* BuildBackForwardButton( + int normal_id, + int active_id, + int highlight_id, + int depressed_id, + const std::wstring& localized_tooltip); + + // Starts a timer to show the dropdown menu. + static gboolean OnBackForwardPressEvent(GtkWidget* button, + GdkEventButton* event, + BrowserToolbarGtk* toolbar); + + // Shows the dropdown menu when the timer fires. |button_type| refers to the + // click that originated the button press event. + void ShowBackForwardMenu(GtkWidget* button, gint button_type); + + // The back/forward menu gets reset every time it is shown. + scoped_ptr<MenuGtk> back_forward_menu_; + + scoped_ptr<BackForwardMenuModelGtk> back_menu_model_; + scoped_ptr<BackForwardMenuModelGtk> forward_menu_model_; + + ScopedRunnableMethodFactory<BrowserToolbarGtk> show_menu_factory_; }; #endif // CHROME_BROWSER_GTK_BROWSER_TOOLBAR_VIEW_GTK_H_ diff --git a/chrome/browser/gtk/menu_gtk.cc b/chrome/browser/gtk/menu_gtk.cc index 7eaab60..db8da36 100644 --- a/chrome/browser/gtk/menu_gtk.cc +++ b/chrome/browser/gtk/menu_gtk.cc @@ -15,6 +15,12 @@ MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, BuildMenuIn(menu_, menu_data); } +MenuGtk::MenuGtk(MenuGtk::Delegate* delegate) + : delegate_(delegate), + menu_(gtk_menu_new()) { + BuildMenuFromDelegate(); +} + MenuGtk::~MenuGtk() { g_object_unref(menu_); } @@ -23,13 +29,17 @@ void MenuGtk::Popup(GtkWidget* widget, GdkEvent* event) { DCHECK(event->type == GDK_BUTTON_PRESS) << "Non-button press event sent to RunMenuAt"; + GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event); + Popup(widget, event_button->button, event_button->time); +} + +void MenuGtk::Popup(GtkWidget* widget, gint button_type, guint32 timestamp) { gtk_container_foreach(GTK_CONTAINER(menu_), SetMenuItemInfo, this); - GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event); gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, MenuPositionFunc, widget, - event_button->button, event_button->time); + button_type, timestamp); } void MenuGtk::BuildMenuIn(GtkWidget* menu, @@ -79,7 +89,33 @@ void MenuGtk::BuildMenuIn(GtkWidget* menu, } } -/* static */ +void MenuGtk::BuildMenuFromDelegate() { + // Note that the menu IDs start at 1, not 0. + for (int i = 1; i <= delegate_->GetItemCount(); ++i) { + GtkWidget* menu_item = NULL; + + if (delegate_->IsItemSeparator(i)) { + menu_item = gtk_separator_menu_item_new(); + } else if (delegate_->HasIcon(i)) { + menu_item = gtk_image_menu_item_new_with_label( + delegate_->GetLabel(i).c_str()); + // TODO(port): set the image with delegate->GetIcon() + } else { + menu_item = gtk_menu_item_new_with_label(delegate_->GetLabel(i).c_str()); + } + + g_object_set_data(G_OBJECT(menu_item), "menu-id", + reinterpret_cast<void*>(i)); + + g_signal_connect(G_OBJECT(menu_item), "activate", + G_CALLBACK(OnMenuItemActivatedById), this); + + gtk_widget_show(menu_item); + gtk_menu_append(menu_, menu_item); + } +} + +// static void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) { // We receive activation messages when highlighting a menu that has a // submenu. Ignore them. @@ -91,7 +127,18 @@ void MenuGtk::OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu) { } } -/* static */ +// static +void MenuGtk::OnMenuItemActivatedById(GtkMenuItem* menuitem, MenuGtk* menu) { + // We receive activation messages when highlighting a menu that has a + // submenu. Ignore them. + if (!gtk_menu_item_get_submenu(menuitem)) { + int id = reinterpret_cast<int>( + g_object_get_data(G_OBJECT(menuitem), "menu-id")); + menu->delegate_->ExecuteCommand(id); + } +} + +// static void MenuGtk::MenuPositionFunc(GtkMenu* menu, int* x, int* y, @@ -110,10 +157,17 @@ void MenuGtk::MenuPositionFunc(GtkMenu* menu, gdk_screen_get_monitor_geometry(screen, monitor_num, &monitor); gdk_window_get_origin(widget->window, x, y); - *x += widget->allocation.x + widget->allocation.width; + *x += widget->allocation.x; *y += widget->allocation.y + widget->allocation.height; - *x -= menu_req.width; + // g_object_get_data() returns NULL if no such object is found. |left_align| + // acts as a boolean, but we can't actually cast it to bool because gcc + // complains about losing precision. + void* left_align = + g_object_get_data(G_OBJECT(widget), "left-align-popup"); + + if (!left_align) + *x += widget->allocation.width - menu_req.width; // TODO(erg): Deal with this scrolling off the bottom of the screen. @@ -123,7 +177,7 @@ void MenuGtk::MenuPositionFunc(GtkMenu* menu, *push_in = FALSE; } -/* static */ +// static void MenuGtk::SetMenuItemInfo(GtkWidget* widget, void* raw_menu) { MenuGtk* menu = static_cast<MenuGtk*>(raw_menu); const MenuCreateMaterial* data = diff --git a/chrome/browser/gtk/menu_gtk.h b/chrome/browser/gtk/menu_gtk.h index 462c122..bef318f 100644 --- a/chrome/browser/gtk/menu_gtk.h +++ b/chrome/browser/gtk/menu_gtk.h @@ -6,9 +6,12 @@ #define CHROME_BROWSER_GTK_MENU_GTK_H_ #include <gtk/gtk.h> +#include <string> #include "chrome/browser/gtk/standard_menus.h" +class SkBitmap; + class MenuGtk { public: // Delegate class that lets another class control the status of the menu. @@ -19,17 +22,32 @@ class MenuGtk { // Returns whether the menu item for this command should be enabled. virtual bool IsCommandEnabled(int command_id) const = 0; - // Returns whether this command. - virtual bool IsItemChecked(int command_id) const = 0; + // Returns whether this command is checked (for checkbox menu items only). + virtual bool IsItemChecked(int command_id) const { return false; } // Executes the command. virtual void ExecuteCommand(int command_id) = 0; + + // Functions needed for creation of non-static menus. + virtual int GetItemCount() const { return 0; } + virtual bool IsItemSeparator(int command_id) const { return false; } + virtual std::string GetLabel(int command_id) const { return std::string(); } + virtual bool HasIcon(int command_id) const { return false; } + virtual const SkBitmap* GetIcon(int command_id) const { return NULL; } }; + // Builds a MenuGtk that uses |delegate| to perform actions and |menu_data| + // to create the menu. MenuGtk(MenuGtk::Delegate* delegate, const MenuCreateMaterial* menu_data); + // Builds a MenuGtk that uses |delegate| to create the menu as well as perform + // actions. + explicit MenuGtk(MenuGtk::Delegate* delegate); ~MenuGtk(); - // Displays the menu + // Displays the menu. |timestamp| is the time of activation. + void Popup(GtkWidget* widget, gint button_type, guint32 timestamp); + + // Displays the menu using the button type and timestamp of |event|. void Popup(GtkWidget* widget, GdkEvent* event); private: @@ -37,10 +55,23 @@ class MenuGtk { // of GtkMenuItems. void BuildMenuIn(GtkWidget* menu, const MenuCreateMaterial* menu_data); - // Callback for when a menu item is clicked. + // A function that creates a GtkMenu from |delegate_|. This function is not + // recursive and does not support sub-menus. + void BuildMenuFromDelegate(); + + // Callback for when a menu item is clicked. Used when the menu is created + // via a MenuCreateMaterial. static void OnMenuItemActivated(GtkMenuItem* menuitem, MenuGtk* menu); + // Callback for when a menu item is clicked. Used when the menu is created + // via |delegate_|. + static void OnMenuItemActivatedById(GtkMenuItem* menuitem, MenuGtk* menu); + // Repositions the menu to be right under the button. + // Alignment is set as object data on |void_widget| with the tag "left_align". + // If "left_align" is true, it aligns the left side of the menu with the left + // side of the button. Otherwise it aligns the right side of the menu with the + // right side of the button. static void MenuPositionFunc(GtkMenu* menu, int* x, int* y, @@ -59,3 +90,4 @@ class MenuGtk { }; #endif // CHROME_BROWSER_GTK_MENU_GTK_H_ + |