summaryrefslogtreecommitdiffstats
path: root/views/controls/menu/native_menu_win.cc
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-09 23:58:02 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-09 23:58:02 +0000
commit21433c86e0f0acc4faa8194c5a561c80e260024f (patch)
tree3968ee16eae150ab0ad7423032b0ae7bc720b57b /views/controls/menu/native_menu_win.cc
parent83119ed160f4203cbb93d83ecf175dfcf0dc3219 (diff)
downloadchromium_src-21433c86e0f0acc4faa8194c5a561c80e260024f.zip
chromium_src-21433c86e0f0acc4faa8194c5a561c80e260024f.tar.gz
chromium_src-21433c86e0f0acc4faa8194c5a561c80e260024f.tar.bz2
Remove Menu2Delegate interface and fold methods onto Menu2Model instead.
Enhance SimpleMenuModel::Delegate interface to support additional options required by the above. Make MenuHostWindow process WM_MENUCOMMAND and WM_MENUSELECT - the first so we can determine which index was selected, the second so we can track highlight changes within a menu. Convert Tab's context menu back to the windows native menu. This will make my life easier when I upgrade chrome_menu.cc to the new API if only the bookmarks menus/context menus are using it. BUG=none TEST=page, app menus again, context menu for tabs. open a bunch of tabs, open this page: http://bengoodger.dreamhosters.com/software/chrome/cxmenutest.html, close that tab then right click on the menu quickly. should not crash! Review URL: http://codereview.chromium.org/118426 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17996 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/controls/menu/native_menu_win.cc')
-rw-r--r--views/controls/menu/native_menu_win.cc98
1 files changed, 80 insertions, 18 deletions
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