diff options
-rw-r--r-- | chrome/browser/views/frame/browser_view.cc | 13 | ||||
-rw-r--r-- | chrome/browser/views/frame/browser_view.h | 5 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab.cc | 152 | ||||
-rw-r--r-- | chrome/browser/views/tabs/tab.h | 10 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.cc | 30 | ||||
-rw-r--r-- | chrome/browser/views/toolbar_view.h | 10 | ||||
-rw-r--r-- | views/controls/menu/menu_2.cc | 7 | ||||
-rw-r--r-- | views/controls/menu/menu_2.h | 22 | ||||
-rw-r--r-- | views/controls/menu/menu_wrapper.h | 3 | ||||
-rw-r--r-- | views/controls/menu/native_menu_gtk.cc | 16 | ||||
-rw-r--r-- | views/controls/menu/native_menu_gtk.h | 6 | ||||
-rw-r--r-- | views/controls/menu/native_menu_win.cc | 98 | ||||
-rw-r--r-- | views/controls/menu/native_menu_win.h | 8 | ||||
-rw-r--r-- | views/controls/menu/simple_menu_model.cc | 10 | ||||
-rw-r--r-- | views/controls/menu/simple_menu_model.h | 17 |
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: |