summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/views/frame/browser_view.cc13
-rw-r--r--chrome/browser/views/frame/browser_view.h5
-rw-r--r--chrome/browser/views/tabs/tab.cc152
-rw-r--r--chrome/browser/views/tabs/tab.h10
-rw-r--r--chrome/browser/views/toolbar_view.cc30
-rw-r--r--chrome/browser/views/toolbar_view.h10
-rw-r--r--views/controls/menu/menu_2.cc7
-rw-r--r--views/controls/menu/menu_2.h22
-rw-r--r--views/controls/menu/menu_wrapper.h3
-rw-r--r--views/controls/menu/native_menu_gtk.cc16
-rw-r--r--views/controls/menu/native_menu_gtk.h6
-rw-r--r--views/controls/menu/native_menu_win.cc98
-rw-r--r--views/controls/menu/native_menu_win.h8
-rw-r--r--views/controls/menu/simple_menu_model.cc10
-rw-r--r--views/controls/menu/simple_menu_model.h17
15 files changed, 215 insertions, 192 deletions
diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc
index de8d082..2665610 100644
--- a/chrome/browser/views/frame/browser_view.cc
+++ b/chrome/browser/views/frame/browser_view.cc
@@ -976,13 +976,6 @@ void BrowserView::TabStripEmpty() {
///////////////////////////////////////////////////////////////////////////////
// BrowserView, views::SimpleMenuModel::Delegate implementation:
-void BrowserView::ExecuteCommand(views::Menu2Model* model, int command_id) {
- browser_->ExecuteCommand(command_id);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// BrowserView, views::SimpleMenuModel::Delegate implementation:
-
bool BrowserView::IsCommandIdChecked(int command_id) const {
// TODO(beng): encoding menu.
// No items in our system menu are check-able.
@@ -1017,6 +1010,10 @@ std::wstring BrowserView::GetLabelForCommandId(int command_id) const {
return l10n_util::GetString(string_id);
}
+void BrowserView::ExecuteCommand(int command_id) {
+ browser_->ExecuteCommand(command_id);
+}
+
///////////////////////////////////////////////////////////////////////////////
// BrowserView, views::WindowDelegate implementation:
@@ -1386,7 +1383,7 @@ void BrowserView::InitSystemMenu() {
else
BuildSystemMenuForPopupWindow();
system_menu_.reset(
- new views::NativeMenuWin(system_menu_contents_.get(), this,
+ new views::NativeMenuWin(system_menu_contents_.get(),
frame_->GetWindow()->GetNativeWindow()));
system_menu_->Rebuild();
}
diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h
index a2e705c..a6c134b 100644
--- a/chrome/browser/views/frame/browser_view.h
+++ b/chrome/browser/views/frame/browser_view.h
@@ -57,7 +57,6 @@ class BrowserView : public BrowserWindow,
public BrowserWindowTesting,
public NotificationObserver,
public TabStripModelObserver,
- public views::Menu2Delegate,
public views::SimpleMenuModel::Delegate,
public views::WindowDelegate,
public views::ClientView {
@@ -257,9 +256,6 @@ class BrowserView : public BrowserWindow,
bool user_gesture);
virtual void TabStripEmpty();
- // Overridden from views::Menu2Delegate:
- virtual void ExecuteCommand(views::Menu2Model* model, int command_id);
-
// Overridden from views::SimpleMenuModel::Delegate:
virtual bool IsCommandIdChecked(int command_id) const;
virtual bool IsCommandIdEnabled(int command_id) const;
@@ -267,6 +263,7 @@ class BrowserView : public BrowserWindow,
views::Accelerator* accelerator);
virtual bool IsLabelForCommandIdDynamic(int command_id) const;
virtual std::wstring GetLabelForCommandId(int command_id) const;
+ virtual void ExecuteCommand(int command_id);
// Overridden from views::WindowDelegate:
virtual bool CanResize() const;
diff --git a/chrome/browser/views/tabs/tab.cc b/chrome/browser/views/tabs/tab.cc
index c15e855..8e9cf2d 100644
--- a/chrome/browser/views/tabs/tab.cc
+++ b/chrome/browser/views/tabs/tab.cc
@@ -11,7 +11,7 @@
#include "app/resource_bundle.h"
#include "base/gfx/size.h"
#include "grit/generated_resources.h"
-#include "views/controls/menu/chrome_menu.h"
+#include "views/controls/menu/simple_menu_model.h"
#include "views/widget/tooltip_manager.h"
#include "views/widget/widget.h"
@@ -21,94 +21,81 @@ static const SkScalar kTabCapWidth = 15;
static const SkScalar kTabTopCurveWidth = 4;
static const SkScalar kTabBottomCurveWidth = 3;
-class Tab::ContextMenuController : public views::MenuDelegate {
+class Tab::TabContextMenuContents : public views::SimpleMenuModel,
+ public views::SimpleMenuModel::Delegate {
public:
- explicit ContextMenuController(Tab* tab)
- : tab_(tab),
+ explicit TabContextMenuContents(Tab* tab)
+ : SimpleMenuModel(this),
+ tab_(tab),
last_command_(TabStripModel::CommandFirst) {
- menu_.reset(new views::MenuItemView(this));
- menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab,
- l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB));
- menu_->AppendSeparator();
- menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload,
- l10n_util::GetString(IDS_TAB_CXMENU_RELOAD));
- menu_->AppendMenuItemWithLabel(
- TabStripModel::CommandDuplicate,
- l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE));
- menu_->AppendSeparator();
- menu_->AppendMenuItemWithLabel(
- TabStripModel::CommandCloseTab,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB));
- menu_->AppendMenuItemWithLabel(
- TabStripModel::CommandCloseOtherTabs,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS));
- menu_->AppendMenuItemWithLabel(
- TabStripModel::CommandCloseTabsToRight,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT));
- menu_->AppendMenuItemWithLabel(
- TabStripModel::CommandCloseTabsOpenedBy,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY));
- menu_->AppendMenuItemWithLabel(
- TabStripModel::CommandRestoreTab, l10n_util::GetString(IDS_RESTORE_TAB));
+ Build();
}
-
- void RunMenuAt(int x, int y) {
- views::MenuItemView::AnchorPosition anchor =
- (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
- views::MenuItemView::TOPRIGHT : views::MenuItemView::TOPLEFT;
- menu_->RunMenuAt(tab_->GetWidget()->GetNativeView(), gfx::Rect(x, y, 0, 0),
- anchor, true);
- if (tab_)
- tab_->ContextMenuClosed();
- delete this;
+ virtual ~TabContextMenuContents() {
+ menu_->CancelMenu();
+ tab_->delegate()->StopAllHighlighting();
}
- void Cancel() {
- tab_ = NULL;
- menu_->Cancel();
+ void RunMenuAt(const gfx::Point& point) {
+ // Save a pointer to delegate before we call RunMenuAt, because it runs a
+ // nested message loop that may not return until after we are deleted.
+ Tab::TabDelegate* delegate = tab_->delegate();
+ menu_->RunMenuAt(point, views::Menu2::ALIGN_TOPLEFT);
+ // We could be gone now. Assume |this| is junk!
+ if (delegate)
+ delegate->StopAllHighlighting();
}
- private:
- virtual ~ContextMenuController() {
+ // Overridden from views::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const {
+ return false;
}
-
- // views::MenuDelegate implementation:
- virtual bool IsCommandEnabled(int id) const {
- // The MenuItemView used to contain the contents of the Context Menu itself
- // has a command id of 0, and it will check to see if it's enabled for
- // some reason during its construction. The TabStripModel can't handle
- // command indices it doesn't know about, so we need to filter this out
- // here.
- if (id == 0 || !tab_)
- return false;
- return tab_->delegate()->IsCommandEnabledForTab(
- static_cast<TabStripModel::ContextMenuCommand>(id),
+ virtual bool IsCommandIdEnabled(int command_id) const {
+ return tab_ && tab_->delegate()->IsCommandEnabledForTab(
+ static_cast<TabStripModel::ContextMenuCommand>(command_id),
tab_);
}
-
- virtual void ExecuteCommand(int id) {
+ virtual bool GetAcceleratorForCommandId(
+ int command_id,
+ views::Accelerator* accelerator) {
+ return tab_->GetWidget()->GetAccelerator(command_id, accelerator);
+ }
+ virtual void CommandIdHighlighted(int command_id) {
if (!tab_)
return;
- tab_->delegate()->ExecuteCommandForTab(
- static_cast<TabStripModel::ContextMenuCommand>(id),
- tab_);
+ tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
+ last_command_ = static_cast<TabStripModel::ContextMenuCommand>(command_id);
+ tab_->delegate()->StartHighlightTabsForCommand(last_command_, tab_);
}
-
- virtual void SelectionChanged(views::MenuItemView* menu) {
+ virtual void ExecuteCommand(int command_id) {
if (!tab_)
return;
-
- TabStripModel::ContextMenuCommand command =
- static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand());
- tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
- last_command_ = command;
- tab_->delegate()->StartHighlightTabsForCommand(command, tab_);
+ tab_->delegate()->ExecuteCommandForTab(
+ static_cast<TabStripModel::ContextMenuCommand>(command_id),
+ tab_);
}
private:
- // The context menu.
- scoped_ptr<views::MenuItemView> menu_;
+ void Build() {
+ AddItemWithStringId(TabStripModel::CommandNewTab, IDS_TAB_CXMENU_NEWTAB);
+ AddSeparator();
+ AddItemWithStringId(TabStripModel::CommandReload, IDS_TAB_CXMENU_RELOAD);
+ AddItemWithStringId(TabStripModel::CommandDuplicate,
+ IDS_TAB_CXMENU_DUPLICATE);
+ AddSeparator();
+ AddItemWithStringId(TabStripModel::CommandCloseTab,
+ IDS_TAB_CXMENU_CLOSETAB);
+ AddItemWithStringId(TabStripModel::CommandCloseOtherTabs,
+ IDS_TAB_CXMENU_CLOSEOTHERTABS);
+ AddItemWithStringId(TabStripModel::CommandCloseTabsToRight,
+ IDS_TAB_CXMENU_CLOSETABSTORIGHT);
+ AddItemWithStringId(TabStripModel::CommandCloseTabsOpenedBy,
+ IDS_TAB_CXMENU_CLOSETABSOPENEDBY);
+ AddItemWithStringId(TabStripModel::CommandRestoreTab, IDS_RESTORE_TAB);
+ menu_.reset(new views::Menu2(this));
+ }
+
+ scoped_ptr<views::Menu2> menu_;
// The Tab the context menu was brought up for. Set to NULL when the menu
// is canceled.
@@ -118,7 +105,7 @@ class Tab::ContextMenuController : public views::MenuDelegate {
// appropriately as the user moves through the menu.
TabStripModel::ContextMenuCommand last_command_;
- DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
+ DISALLOW_COPY_AND_ASSIGN(TabContextMenuContents);
};
///////////////////////////////////////////////////////////////////////////////
@@ -127,21 +114,13 @@ class Tab::ContextMenuController : public views::MenuDelegate {
Tab::Tab(TabDelegate* delegate)
: TabRenderer(),
delegate_(delegate),
- closing_(false),
- menu_controller_(NULL) {
+ closing_(false) {
close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
close_button()->SetAnimationDuration(0);
SetContextMenuController(this);
}
Tab::~Tab() {
- if (menu_controller_) {
- // The menu is showing. Close the menu.
- menu_controller_->Cancel();
-
- // Invoke this so that we hide the highlight.
- ContextMenuClosed();
- }
}
///////////////////////////////////////////////////////////////////////////////
@@ -233,11 +212,9 @@ bool Tab::GetAccessibleName(std::wstring* name) {
void Tab::ShowContextMenu(views::View* source, int x, int y,
bool is_mouse_gesture) {
- if (menu_controller_)
- return;
- menu_controller_ = new ContextMenuController(this);
- menu_controller_->RunMenuAt(x, y);
- // ContextMenuController takes care of deleting itself.
+ if (!context_menu_contents_.get())
+ context_menu_contents_.reset(new TabContextMenuContents(this));
+ context_menu_contents_->RunMenuAt(gfx::Point(x, y));
}
///////////////////////////////////////////////////////////////////////////////
@@ -276,8 +253,3 @@ void Tab::MakePathForTab(gfx::Path* path) const {
path->lineTo(0, h);
path->close();
}
-
-void Tab::ContextMenuClosed() {
- delegate()->StopAllHighlighting();
- menu_controller_ = NULL;
-}
diff --git a/chrome/browser/views/tabs/tab.h b/chrome/browser/views/tabs/tab.h
index 920a849..ad918a2 100644
--- a/chrome/browser/views/tabs/tab.h
+++ b/chrome/browser/views/tabs/tab.h
@@ -89,10 +89,6 @@ class Tab : public TabRenderer,
virtual bool IsSelected() const;
private:
- class ContextMenuController;
-
- friend class ContextMenuController;
-
// views::View overrides:
virtual bool HasHitTestMask() const;
virtual void GetHitTestMask(gfx::Path* mask) const;
@@ -119,9 +115,6 @@ class Tab : public TabRenderer,
// representation. Used by GetViewForPoint for hit-testing.
void MakePathForTab(gfx::Path* path) const;
- // Invoked when the context menu closes.
- void ContextMenuClosed();
-
// An instance of a delegate object that can perform various actions based on
// user gestures.
TabDelegate* delegate_;
@@ -130,7 +123,8 @@ class Tab : public TabRenderer,
bool closing_;
// If non-null it means we're showing a menu for the tab.
- ContextMenuController* menu_controller_;
+ class TabContextMenuContents;
+ scoped_ptr<TabContextMenuContents> context_menu_contents_;
DISALLOW_COPY_AND_ASSIGN(Tab);
};
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index 986aab5..3d64b1d 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -134,16 +134,10 @@ bool EncodingMenuModel::GetAcceleratorForCommandId(
return false;
}
-bool EncodingMenuModel::IsLabelForCommandIdDynamic(int command_id) const {
- // None of our items have dynamic labels.
- return false;
-}
-
-std::wstring EncodingMenuModel::GetLabelForCommandId(int command_id) const {
- return std::wstring();
+void EncodingMenuModel::ExecuteCommand(int command_id) {
+ browser_->ExecuteCommand(command_id);
}
-
////////////////////////////////////////////////////////////////////////////////
// EncodingMenuModel
@@ -417,13 +411,6 @@ void ToolbarView::Observe(NotificationType type,
}
////////////////////////////////////////////////////////////////////////////////
-// ToolbarView, views::Menu2Delegate implementation:
-
-void ToolbarView::ExecuteCommand(views::Menu2Model* model, int command_id) {
- browser_->ExecuteCommand(command_id);
-}
-
-////////////////////////////////////////////////////////////////////////////////
// ToolbarView, views::SimpleMenuModel::Delegate implementation:
bool ToolbarView::IsCommandIdChecked(int command_id) const {
@@ -456,13 +443,8 @@ bool ToolbarView::GetAcceleratorForCommandId(int command_id,
return GetWidget()->GetAccelerator(command_id, accelerator);
}
-bool ToolbarView::IsLabelForCommandIdDynamic(int command_id) const {
- // None of our menu items have dynamic labels.
- return false;
-}
-
-std::wstring ToolbarView::GetLabelForCommandId(int command_id) const {
- return std::wstring();
+void ToolbarView::ExecuteCommand(int command_id) {
+ browser_->ExecuteCommand(command_id);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1057,7 +1039,7 @@ void ToolbarView::CreatePageMenu() {
page_menu_contents_->AddSeparator();
page_menu_contents_->AddItemWithStringId(IDC_REPORT_BUG, IDS_REPORT_BUG);
- page_menu_menu_.reset(new views::Menu2(page_menu_contents_.get(), this));
+ page_menu_menu_.reset(new views::Menu2(page_menu_contents_.get()));
}
#if defined(OS_WIN)
@@ -1121,5 +1103,5 @@ void ToolbarView::CreateAppMenu() {
app_menu_contents_->AddSeparator();
app_menu_contents_->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
- app_menu_menu_.reset(new views::Menu2(app_menu_contents_.get(), this));
+ app_menu_menu_.reset(new views::Menu2(app_menu_contents_.get()));
}
diff --git a/chrome/browser/views/toolbar_view.h b/chrome/browser/views/toolbar_view.h
index 18a6365..169448b 100644
--- a/chrome/browser/views/toolbar_view.h
+++ b/chrome/browser/views/toolbar_view.h
@@ -41,8 +41,7 @@ class EncodingMenuModel : public views::SimpleMenuModel,
virtual bool IsCommandIdEnabled(int command_id) const;
virtual bool GetAcceleratorForCommandId(int command_id,
views::Accelerator* accelerator);
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
- virtual std::wstring GetLabelForCommandId(int command_id) const;
+ virtual void ExecuteCommand(int command_id);
private:
void Build();
@@ -67,7 +66,6 @@ class ZoomMenuModel : public views::SimpleMenuModel {
class ToolbarView : public views::View,
public views::ViewMenuDelegate,
public views::DragController,
- public views::Menu2Delegate,
public views::SimpleMenuModel::Delegate,
public LocationBarView::Delegate,
public NotificationObserver,
@@ -136,16 +134,12 @@ class ToolbarView : public views::View,
const NotificationSource& source,
const NotificationDetails& details);
- // Overridden from views::Menu2Delegate:
- virtual void ExecuteCommand(views::Menu2Model* model, int command_id);
-
// Overridden from views::SimpleMenuModel::Delegate:
virtual bool IsCommandIdChecked(int command_id) const;
virtual bool IsCommandIdEnabled(int command_id) const;
virtual bool GetAcceleratorForCommandId(int command_id,
views::Accelerator* accelerator);
- virtual bool IsLabelForCommandIdDynamic(int command_id) const;
- virtual std::wstring GetLabelForCommandId(int command_id) const;
+ virtual void ExecuteCommand(int command_id);
// Overridden from views::View:
virtual gfx::Size GetPreferredSize();
diff --git a/views/controls/menu/menu_2.cc b/views/controls/menu/menu_2.cc
index 7d2fa8a..8ce63b6 100644
--- a/views/controls/menu/menu_2.cc
+++ b/views/controls/menu/menu_2.cc
@@ -35,9 +35,8 @@ bool Menu2Model::GetModelAndIndexForCommandId(int command_id,
////////////////////////////////////////////////////////////////////////////////
// Menu2, public:
-Menu2::Menu2(Menu2Model* model, Menu2Delegate* delegate)
+Menu2::Menu2(Menu2Model* model)
: model_(model),
- delegate_(delegate),
ALLOW_THIS_IN_INITIALIZER_LIST(
wrapper_(MenuWrapper::CreateWrapper(this))) {
Rebuild();
@@ -51,6 +50,10 @@ void Menu2::RunMenuAt(const gfx::Point& point, Alignment alignment) {
wrapper_->RunMenuAt(point, alignment);
}
+void Menu2::CancelMenu() {
+ wrapper_->CancelMenu();
+}
+
void Menu2::Rebuild() {
wrapper_->Rebuild();
}
diff --git a/views/controls/menu/menu_2.h b/views/controls/menu/menu_2.h
index b50efd7..a131ee5 100644
--- a/views/controls/menu/menu_2.h
+++ b/views/controls/menu/menu_2.h
@@ -87,6 +87,13 @@ class Menu2Model {
// Returns the model for the submenu at the specified index.
virtual Menu2Model* GetSubmenuModelAt(int index) const = 0;
+ // Called when the highlighted menu item changes to the item at the specified
+ // index.
+ virtual void HighlightChangedTo(int index) = 0;
+
+ // Called when the item at the specified index has been activated.
+ virtual void ActivatedAt(int index) = 0;
+
// Retrieves the model and index that contains a specific command id. Returns
// true if an item with the specified command id is found. |model| is inout,
// and specifies the model to start searching from.
@@ -94,18 +101,10 @@ class Menu2Model {
int* index);
};
-// The Menu2Delegate is an interface implemented by an object that performs
-// tasks that the Menu2 cannot itself.
-class Menu2Delegate {
- public:
- // Executes the command with the specified identifier.
- virtual void ExecuteCommand(Menu2Model* model, int command_id) = 0;
-};
-
// A menu. Populated from a model, and relies on a delegate to execute commands.
class Menu2 {
public:
- Menu2(Menu2Model* model, Menu2Delegate* delegate);
+ explicit Menu2(Menu2Model* model);
virtual ~Menu2() {}
// How the menu is aligned relative to the point it is shown at.
@@ -118,6 +117,9 @@ class Menu2 {
// on the platform and type of menu in use.
void RunMenuAt(const gfx::Point& point, Alignment alignment);
+ // Cancels the active menu.
+ void CancelMenu();
+
// Called when the model supplying data to this menu has changed, and the menu
// must be rebuilt.
void Rebuild();
@@ -131,11 +133,9 @@ class Menu2 {
// Accessors.
Menu2Model* model() const { return model_; }
- Menu2Delegate* delegate() const { return delegate_; }
private:
Menu2Model* model_;
- Menu2Delegate* delegate_;
// The object that actually implements the menu.
MenuWrapper* wrapper_;
diff --git a/views/controls/menu/menu_wrapper.h b/views/controls/menu/menu_wrapper.h
index f418703..3786002 100644
--- a/views/controls/menu/menu_wrapper.h
+++ b/views/controls/menu/menu_wrapper.h
@@ -24,6 +24,9 @@ class MenuWrapper {
// on the platform.
virtual void RunMenuAt(const gfx::Point& point, int alignment) = 0;
+ // Cancels the active menu.
+ virtual void CancelMenu() = 0;
+
// Called when the model supplying data to this menu has changed, and the menu
// must be rebuilt.
virtual void Rebuild() = 0;
diff --git a/views/controls/menu/native_menu_gtk.cc b/views/controls/menu/native_menu_gtk.cc
index 4221e6b..c81f04b 100644
--- a/views/controls/menu/native_menu_gtk.cc
+++ b/views/controls/menu/native_menu_gtk.cc
@@ -59,11 +59,7 @@ namespace views {
////////////////////////////////////////////////////////////////////////////////
// NativeMenuGtk, public:
-NativeMenuGtk::NativeMenuGtk(Menu2Model* model,
- Menu2Delegate* delegate)
- : model_(model),
- delegate_(delegate),
- menu_(NULL) {
+NativeMenuGtk::NativeMenuGtk(Menu2Model* model) : model_(model), menu_(NULL) {
}
NativeMenuGtk::~NativeMenuGtk() {
@@ -80,6 +76,10 @@ void NativeMenuGtk::RunMenuAt(const gfx::Point& point, int alignment) {
gtk_get_current_event_time());
}
+void NativeMenuGtk::CancelMenu() {
+ NOTIMPLEMENTED();
+}
+
void NativeMenuGtk::Rebuild() {
ResetMenu();
@@ -144,7 +144,7 @@ void NativeMenuGtk::AddMenuItemAt(int index,
if (type == Menu2Model::TYPE_SUBMENU) {
// TODO(beng): we're leaking these objects right now... consider some other
// arrangement.
- Menu2* submenu = new Menu2(model_->GetSubmenuModelAt(index), delegate_);
+ Menu2* submenu = new Menu2(model_->GetSubmenuModelAt(index));
g_object_set_data(G_OBJECT(menu_item), "submenu", submenu);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
submenu->GetNativeMenu());
@@ -212,7 +212,7 @@ void NativeMenuGtk::OnActivate(GtkMenuItem* menu_item) {
"position"));
if (model_->IsEnabledAt(position) &&
MenuTypeCanExecute(model_->GetTypeAt(position))) {
- delegate_->ExecuteCommand(model_, model_->GetCommandIdAt(position));
+ model_->ActivatedAt(position);
}
}
@@ -227,7 +227,7 @@ void NativeMenuGtk::CallActivate(GtkMenuItem* menu_item,
// static
MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) {
- return new NativeMenuGtk(menu->model(), menu->delegate());
+ return new NativeMenuGtk(menu->model());
}
} // namespace views
diff --git a/views/controls/menu/native_menu_gtk.h b/views/controls/menu/native_menu_gtk.h
index 1c311b5..b9fcb45d 100644
--- a/views/controls/menu/native_menu_gtk.h
+++ b/views/controls/menu/native_menu_gtk.h
@@ -12,18 +12,17 @@
namespace views {
class Menu2Model;
-class Menu2Delegate;
// A Gtk implementation of MenuWrapper.
// TODO(beng): rename to MenuGtk once the old class is dead.
class NativeMenuGtk : public MenuWrapper {
public:
- NativeMenuGtk(Menu2Model* model,
- Menu2Delegate* delegate);
+ explicit NativeMenuGtk(Menu2Model* model);
virtual ~NativeMenuGtk();
// Overridden from MenuWrapper:
virtual void RunMenuAt(const gfx::Point& point, int alignment);
+ virtual void CancelMenu();
virtual void Rebuild();
virtual void UpdateStates();
virtual gfx::NativeMenu GetNativeMenu() const;
@@ -47,7 +46,6 @@ class NativeMenuGtk : public MenuWrapper {
static void CallActivate(GtkMenuItem* menu_item, NativeMenuGtk* native_menu);
Menu2Model* model_;
- Menu2Delegate* delegate_;
GtkWidget* menu_;
diff --git a/views/controls/menu/native_menu_win.cc b/views/controls/menu/native_menu_win.cc
index fa2a5f7..bbdd46a 100644
--- a/views/controls/menu/native_menu_win.cc
+++ b/views/controls/menu/native_menu_win.cc
@@ -23,7 +23,8 @@ struct NativeMenuWin::ItemData {
scoped_ptr<Menu2> submenu;
};
-// TODO(beng): bring over owner draw from old menu system.
+// A window that receives messages from Windows relevant to the native menu
+// structure we have constructed in NativeMenuWin.
class NativeMenuWin::MenuHostWindow {
public:
MenuHostWindow() {
@@ -59,11 +60,65 @@ class NativeMenuWin::MenuHostWindow {
registered = true;
}
+ NativeMenuWin* GetNativeMenuWinFromHMENU(HMENU hmenu) const {
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.fMask = MIM_MENUDATA;
+ GetMenuInfo(hmenu, &mi);
+ return reinterpret_cast<NativeMenuWin*>(mi.dwMenuData);
+ }
+
+ // Converts the WPARAM value passed to WM_MENUSELECT into an index
+ // corresponding to the menu item that was selected.
+ int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const {
+ int count = GetMenuItemCount(menu);
+ // For normal command menu items, Windows passes a command id as the LOWORD
+ // of WPARAM for WM_MENUSELECT. We need to walk forward through the menu
+ // items to find an item with a matching ID. Ugh!
+ for (int i = 0; i < count; ++i) {
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_ID;
+ GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii);
+ if (mii.wID == w_param)
+ return i;
+ }
+ // If we didn't find a matching command ID, this means a submenu has been
+ // selected instead, and rather than passing a command ID in
+ // LOWORD(w_param), Windows has actually passed us a position, so we just
+ // return it.
+ return w_param;
+ }
+
+ // Called when the user selects a specific item.
+ void OnMenuCommand(int position, HMENU menu) {
+ GetNativeMenuWinFromHMENU(menu)->model_->ActivatedAt(position);
+ }
+
+ // Called as the user moves their mouse or arrows through the contents of the
+ // menu.
+ void OnMenuSelect(WPARAM w_param, HMENU menu) {
+ int position = GetMenuItemIndexFromWPARAM(menu, w_param);
+ if (position >= 0)
+ GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
+ }
+
bool ProcessWindowMessage(HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param,
LRESULT* l_result) {
+ switch (message) {
+ case WM_MENUCOMMAND:
+ OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
+ *l_result = 0;
+ return true;
+ case WM_MENUSELECT:
+ OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
+ *l_result = 0;
+ return true;
+ // TODO(beng): bring over owner draw from old menu system.
+ }
return false;
}
@@ -97,11 +152,8 @@ const wchar_t* NativeMenuWin::MenuHostWindow::kMenuHostWindowKey =
////////////////////////////////////////////////////////////////////////////////
// NativeMenuWin, public:
-NativeMenuWin::NativeMenuWin(Menu2Model* model,
- Menu2Delegate* delegate,
- HWND system_menu_for)
+NativeMenuWin::NativeMenuWin(Menu2Model* model, HWND system_menu_for)
: model_(model),
- delegate_(delegate),
menu_(NULL),
owner_draw_(false),
system_menu_for_(system_menu_for),
@@ -118,17 +170,16 @@ NativeMenuWin::~NativeMenuWin() {
void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
CreateHostWindow();
UpdateStates();
- UINT flags = TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
+ UINT flags = TPM_LEFTBUTTON | TPM_RECURSE;
flags |= GetAlignmentFlags(alignment);
- UINT selected_command_id = TrackPopupMenuEx(menu_, flags, point.x(),
- point.y(), host_window_->hwnd(),
- NULL);
- if (selected_command_id > 0) {
- // Locate the correct delegate and model to notify about the selection.
- // See comment in GetMenuForCommandId for details.
- NativeMenuWin* menu = GetMenuForCommandId(selected_command_id);
- menu->delegate_->ExecuteCommand(menu->model_, selected_command_id);
- }
+ // Command dispatch is done through WM_MENUCOMMAND, handled by the host
+ // window.
+ TrackPopupMenuEx(menu_, flags, point.x(), point.y(), host_window_->hwnd(),
+ NULL);
+}
+
+void NativeMenuWin::CancelMenu() {
+ EndMenu();
}
void NativeMenuWin::Rebuild() {
@@ -190,8 +241,7 @@ void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
ItemData* item_data = new ItemData;
Menu2Model::ItemType type = model_->GetTypeAt(model_index);
if (type == Menu2Model::TYPE_SUBMENU) {
- item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index),
- delegate_));
+ item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
mii.fMask |= MIIM_SUBMENU;
mii.hSubMenu = item_data->submenu->GetNativeMenu();
} else {
@@ -312,10 +362,22 @@ void NativeMenuWin::ResetNativeMenu() {
if (menu_)
DestroyMenu(menu_);
menu_ = CreatePopupMenu();
+ // Rather than relying on the return value of TrackPopupMenuEx, which is
+ // always a command identifier, instead we tell the menu to notify us via
+ // our host window and the WM_MENUCOMMAND message.
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.fMask = MIM_STYLE | MIM_MENUDATA;
+ mi.dwStyle = MNS_NOTIFYBYPOS;
+ mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this);
+ SetMenuInfo(menu_, &mi);
}
}
void NativeMenuWin::CreateHostWindow() {
+ // This only gets called from RunMenuAt, and as such there is only ever one
+ // host window per menu hierarchy, no matter how many NativeMenuWin objects
+ // exist wrapping submenus.
if (!host_window_.get())
host_window_.reset(new MenuHostWindow());
}
@@ -340,7 +402,7 @@ int SystemMenuModel::GetFirstItemIndex(gfx::NativeMenu native_menu) const {
// static
MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) {
- return new NativeMenuWin(menu->model(), menu->delegate(), NULL);
+ return new NativeMenuWin(menu->model(), NULL);
}
} // namespace views
diff --git a/views/controls/menu/native_menu_win.h b/views/controls/menu/native_menu_win.h
index df0aa63..c22313a 100644
--- a/views/controls/menu/native_menu_win.h
+++ b/views/controls/menu/native_menu_win.h
@@ -13,7 +13,6 @@
namespace views {
-class Menu2Delegate;
class Menu2Model;
// A Windows implementation of MenuWrapper.
@@ -23,13 +22,12 @@ class NativeMenuWin : public MenuWrapper {
// Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
// is non-NULL, the NativeMenuWin wraps the system menu for that window.
// The caller owns the model and the delegate.
- NativeMenuWin(Menu2Model* model,
- Menu2Delegate* delegate,
- HWND system_menu_for);
+ NativeMenuWin(Menu2Model* model, HWND system_menu_for);
virtual ~NativeMenuWin();
// Overridden from MenuWrapper:
virtual void RunMenuAt(const gfx::Point& point, int alignment);
+ virtual void CancelMenu();
virtual void Rebuild();
virtual void UpdateStates();
virtual gfx::NativeMenu GetNativeMenu() const;
@@ -90,7 +88,6 @@ class NativeMenuWin : public MenuWrapper {
// Our attached model and delegate.
Menu2Model* model_;
- Menu2Delegate* delegate_;
HMENU menu_;
@@ -105,6 +102,7 @@ class NativeMenuWin : public MenuWrapper {
// The window that receives notifications from the menu.
class MenuHostWindow;
+ friend MenuHostWindow;
scoped_ptr<MenuHostWindow> host_window_;
// The HWND this menu is the system menu for, or NULL if the menu is not a
diff --git a/views/controls/menu/simple_menu_model.cc b/views/controls/menu/simple_menu_model.cc
index 243b144..1ddc092 100644
--- a/views/controls/menu/simple_menu_model.cc
+++ b/views/controls/menu/simple_menu_model.cc
@@ -122,6 +122,16 @@ bool SimpleMenuModel::IsEnabledAt(int index) const {
return delegate_->IsCommandIdEnabled(command_id);
}
+void SimpleMenuModel::HighlightChangedTo(int index) {
+ if (delegate_)
+ delegate_->CommandIdHighlighted(GetCommandIdAt(index));
+}
+
+void SimpleMenuModel::ActivatedAt(int index) {
+ if (delegate_)
+ delegate_->ExecuteCommand(GetCommandIdAt(index));
+}
+
Menu2Model* SimpleMenuModel::GetSubmenuModelAt(int index) const {
return items_.at(FlipIndex(index)).submenu;
}
diff --git a/views/controls/menu/simple_menu_model.h b/views/controls/menu/simple_menu_model.h
index dbab73f..051de76 100644
--- a/views/controls/menu/simple_menu_model.h
+++ b/views/controls/menu/simple_menu_model.h
@@ -30,8 +30,19 @@ class SimpleMenuModel : public Menu2Model {
views::Accelerator* accelerator) = 0;
// Some command ids have labels that change over time.
- virtual bool IsLabelForCommandIdDynamic(int command_id) const = 0;
- virtual std::wstring GetLabelForCommandId(int command_id) const = 0;
+ virtual bool IsLabelForCommandIdDynamic(int command_id) const {
+ return false;
+ }
+ virtual std::wstring GetLabelForCommandId(int command_id) const {
+ return std::wstring();
+ }
+
+ // Notifies the delegate that the item with the specified command id was
+ // visually highlighted within the menu.
+ virtual void CommandIdHighlighted(int command_id) {}
+
+ // Performs the action associated with the specified command id.
+ virtual void ExecuteCommand(int command_id) = 0;
};
// The Delegate can be NULL, though if it is items can't be checked or
@@ -63,6 +74,8 @@ class SimpleMenuModel : public Menu2Model {
virtual int GetGroupIdAt(int index) const;
virtual bool GetIconAt(int index, SkBitmap* icon) const;
virtual bool IsEnabledAt(int index) const;
+ virtual void HighlightChangedTo(int index);
+ virtual void ActivatedAt(int index);
virtual Menu2Model* GetSubmenuModelAt(int index) const;
protected: