| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "views/controls/menu/native_menu_win.h" | 5 #include "views/controls/menu/native_menu_win.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "app/l10n_util_win.h" | 8 #include "app/l10n_util_win.h" |
| 9 #include "app/win/hwnd_util.h" | 9 #include "app/win/hwnd_util.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" |
| 11 #include "base/stl_util-inl.h" | 12 #include "base/stl_util-inl.h" |
| 13 #include "base/task.h" |
| 12 #include "gfx/canvas_skia.h" | 14 #include "gfx/canvas_skia.h" |
| 13 #include "gfx/font.h" | 15 #include "gfx/font.h" |
| 14 #include "third_party/skia/include/core/SkBitmap.h" | 16 #include "third_party/skia/include/core/SkBitmap.h" |
| 15 #include "ui/base/keycodes/keyboard_codes.h" | 17 #include "ui/base/keycodes/keyboard_codes.h" |
| 16 #include "views/accelerator.h" | 18 #include "views/accelerator.h" |
| 17 #include "views/controls/menu/menu_2.h" | 19 #include "views/controls/menu/menu_2.h" |
| 18 | 20 |
| 19 namespace views { | 21 namespace views { |
| 20 | 22 |
| 21 // The width of an icon, including the pixels between the icon and | 23 // The width of an icon, including the pixels between the icon and |
| (...skipping 23 matching lines...) Expand all Loading... |
| 45 NativeMenuWin* native_menu_win; | 47 NativeMenuWin* native_menu_win; |
| 46 | 48 |
| 47 // The index of the item within the menu's model. | 49 // The index of the item within the menu's model. |
| 48 int model_index; | 50 int model_index; |
| 49 }; | 51 }; |
| 50 | 52 |
| 51 // A window that receives messages from Windows relevant to the native menu | 53 // A window that receives messages from Windows relevant to the native menu |
| 52 // structure we have constructed in NativeMenuWin. | 54 // structure we have constructed in NativeMenuWin. |
| 53 class NativeMenuWin::MenuHostWindow { | 55 class NativeMenuWin::MenuHostWindow { |
| 54 public: | 56 public: |
| 55 MenuHostWindow() { | 57 MenuHostWindow(NativeMenuWin* parent) |
| 58 : parent_(parent), |
| 59 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 56 RegisterClass(); | 60 RegisterClass(); |
| 57 hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName, | 61 hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName, |
| 58 L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); | 62 L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); |
| 59 app::win::SetWindowUserData(hwnd_, this); | 63 app::win::SetWindowUserData(hwnd_, this); |
| 60 } | 64 } |
| 61 | 65 |
| 62 ~MenuHostWindow() { | 66 ~MenuHostWindow() { |
| 63 DestroyWindow(hwnd_); | 67 DestroyWindow(hwnd_); |
| 64 } | 68 } |
| 65 | 69 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 77 wcex.cbSize = sizeof(WNDCLASSEX); | 81 wcex.cbSize = sizeof(WNDCLASSEX); |
| 78 wcex.style = CS_DBLCLKS; | 82 wcex.style = CS_DBLCLKS; |
| 79 wcex.lpfnWndProc = &MenuHostWindowProc; | 83 wcex.lpfnWndProc = &MenuHostWindowProc; |
| 80 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1); | 84 wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1); |
| 81 wcex.lpszClassName = kWindowClassName; | 85 wcex.lpszClassName = kWindowClassName; |
| 82 ATOM clazz = RegisterClassEx(&wcex); | 86 ATOM clazz = RegisterClassEx(&wcex); |
| 83 DCHECK(clazz); | 87 DCHECK(clazz); |
| 84 registered = true; | 88 registered = true; |
| 85 } | 89 } |
| 86 | 90 |
| 87 NativeMenuWin* GetNativeMenuWinFromHMENU(HMENU hmenu) const { | |
| 88 MENUINFO mi = {0}; | |
| 89 mi.cbSize = sizeof(mi); | |
| 90 mi.fMask = MIM_MENUDATA | MIM_STYLE; | |
| 91 GetMenuInfo(hmenu, &mi); | |
| 92 return reinterpret_cast<NativeMenuWin*>(mi.dwMenuData); | |
| 93 } | |
| 94 | |
| 95 // Converts the WPARAM value passed to WM_MENUSELECT into an index | 91 // Converts the WPARAM value passed to WM_MENUSELECT into an index |
| 96 // corresponding to the menu item that was selected. | 92 // corresponding to the menu item that was selected. |
| 97 int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const { | 93 int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const { |
| 98 int count = GetMenuItemCount(menu); | 94 int count = GetMenuItemCount(menu); |
| 99 // For normal command menu items, Windows passes a command id as the LOWORD | 95 // For normal command menu items, Windows passes a command id as the LOWORD |
| 100 // of WPARAM for WM_MENUSELECT. We need to walk forward through the menu | 96 // of WPARAM for WM_MENUSELECT. We need to walk forward through the menu |
| 101 // items to find an item with a matching ID. Ugh! | 97 // items to find an item with a matching ID. Ugh! |
| 102 for (int i = 0; i < count; ++i) { | 98 for (int i = 0; i < count; ++i) { |
| 103 MENUITEMINFO mii = {0}; | 99 MENUITEMINFO mii = {0}; |
| 104 mii.cbSize = sizeof(mii); | 100 mii.cbSize = sizeof(mii); |
| 105 mii.fMask = MIIM_ID; | 101 mii.fMask = MIIM_ID; |
| 106 GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii); | 102 GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii); |
| 107 if (mii.wID == w_param) | 103 if (mii.wID == w_param) |
| 108 return i; | 104 return i; |
| 109 } | 105 } |
| 110 // If we didn't find a matching command ID, this means a submenu has been | 106 // If we didn't find a matching command ID, this means a submenu has been |
| 111 // selected instead, and rather than passing a command ID in | 107 // selected instead, and rather than passing a command ID in |
| 112 // LOWORD(w_param), Windows has actually passed us a position, so we just | 108 // LOWORD(w_param), Windows has actually passed us a position, so we just |
| 113 // return it. | 109 // return it. |
| 114 return w_param; | 110 return w_param; |
| 115 } | 111 } |
| 116 | 112 |
| 117 NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) { | 113 NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) { |
| 118 return reinterpret_cast<NativeMenuWin::ItemData*>(item_data); | 114 return reinterpret_cast<NativeMenuWin::ItemData*>(item_data); |
| 119 } | 115 } |
| 120 | 116 |
| 121 // Called when the user selects a specific item. | 117 // Called when the user selects a specific item. |
| 122 void OnMenuCommand(int position, HMENU menu) { | 118 void OnMenuCommand(int position, HMENU menu) { |
| 123 NativeMenuWin* intergoat = GetNativeMenuWinFromHMENU(menu); | 119 parent_->model_->ActivatedAt(position); |
| 124 ui::MenuModel* model = intergoat->model_; | |
| 125 model->ActivatedAt(position); | |
| 126 } | 120 } |
| 127 | 121 |
| 128 // Called as the user moves their mouse or arrows through the contents of the | 122 // Called as the user moves their mouse or arrows through the contents of the |
| 129 // menu. | 123 // menu. |
| 130 void OnMenuSelect(WPARAM w_param, HMENU menu) { | 124 void OnMenuSelect(WPARAM w_param, HMENU menu) { |
| 131 if (!menu) | |
| 132 return; // menu is null when closing on XP. | |
| 133 | |
| 134 int position = GetMenuItemIndexFromWPARAM(menu, w_param); | 125 int position = GetMenuItemIndexFromWPARAM(menu, w_param); |
| 135 if (position >= 0) | 126 if (position >= 0) |
| 136 GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position); | 127 parent_->model_->HighlightChangedTo(position); |
| 137 } | 128 } |
| 138 | 129 |
| 139 // Called by Windows to measure the size of an owner-drawn menu item. | 130 // Called by Windows to measure the size of an owner-drawn menu item. |
| 140 void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) { | 131 void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) { |
| 141 NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData); | 132 NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData); |
| 142 if (data) { | 133 if (data) { |
| 143 gfx::Font font; | 134 gfx::Font font; |
| 144 measure_item_struct->itemWidth = font.GetStringWidth(data->label) + | 135 measure_item_struct->itemWidth = font.GetStringWidth(data->label) + |
| 145 kIconWidth + kItemLeftMargin + kItemRightMargin - | 136 kIconWidth + kItemLeftMargin + kItemRightMargin - |
| 146 GetSystemMetrics(SM_CXMENUCHECK); | 137 GetSystemMetrics(SM_CXMENUCHECK); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 // Draw the separator | 227 // Draw the separator |
| 237 draw_item_struct->rcItem.top += | 228 draw_item_struct->rcItem.top += |
| 238 (draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3; | 229 (draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3; |
| 239 DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP); | 230 DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP); |
| 240 } | 231 } |
| 241 | 232 |
| 242 SetBkColor(dc, prev_bg_color); | 233 SetBkColor(dc, prev_bg_color); |
| 243 SetTextColor(dc, prev_text_color); | 234 SetTextColor(dc, prev_text_color); |
| 244 } | 235 } |
| 245 | 236 |
| 237 void OnMenuClosed() { |
| 238 parent_->model_->MenuClosed(); |
| 239 } |
| 240 |
| 246 bool ProcessWindowMessage(HWND window, | 241 bool ProcessWindowMessage(HWND window, |
| 247 UINT message, | 242 UINT message, |
| 248 WPARAM w_param, | 243 WPARAM w_param, |
| 249 LPARAM l_param, | 244 LPARAM l_param, |
| 250 LRESULT* l_result) { | 245 LRESULT* l_result) { |
| 251 switch (message) { | 246 switch (message) { |
| 252 case WM_MENUCOMMAND: | 247 case WM_MENUCOMMAND: |
| 253 OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param)); | 248 OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param)); |
| 254 *l_result = 0; | 249 *l_result = 0; |
| 255 return true; | 250 return true; |
| 256 case WM_MENUSELECT: | 251 case WM_MENUSELECT: |
| 257 OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param)); | 252 OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param)); |
| 258 *l_result = 0; | 253 *l_result = 0; |
| 259 return true; | 254 return true; |
| 260 case WM_MEASUREITEM: | 255 case WM_MEASUREITEM: |
| 261 OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param)); | 256 OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param)); |
| 262 *l_result = 0; | 257 *l_result = 0; |
| 263 return true; | 258 return true; |
| 264 case WM_DRAWITEM: | 259 case WM_DRAWITEM: |
| 265 OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param)); | 260 OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param)); |
| 266 *l_result = 0; | 261 *l_result = 0; |
| 267 return true; | 262 return true; |
| 263 case WM_EXITMENULOOP: |
| 264 // WM_MENUCOMMAND comes after this message, but still in the same |
| 265 // callstack. So use PostTask to guarantee that we'll tell the model |
| 266 // that the menus is closed after any other notifications. |
| 267 MessageLoop::current()->PostTask( |
| 268 FROM_HERE, |
| 269 method_factory_.NewRunnableMethod(&MenuHostWindow::OnMenuClosed)); |
| 270 return true; |
| 268 // TODO(beng): bring over owner draw from old menu system. | 271 // TODO(beng): bring over owner draw from old menu system. |
| 269 } | 272 } |
| 270 return false; | 273 return false; |
| 271 } | 274 } |
| 272 | 275 |
| 273 static LRESULT CALLBACK MenuHostWindowProc(HWND window, | 276 static LRESULT CALLBACK MenuHostWindowProc(HWND window, |
| 274 UINT message, | 277 UINT message, |
| 275 WPARAM w_param, | 278 WPARAM w_param, |
| 276 LPARAM l_param) { | 279 LPARAM l_param) { |
| 277 MenuHostWindow* host = | 280 MenuHostWindow* host = |
| 278 reinterpret_cast<MenuHostWindow*>(app::win::GetWindowUserData(window)); | 281 reinterpret_cast<MenuHostWindow*>(app::win::GetWindowUserData(window)); |
| 279 // host is null during initial construction. | 282 // host is null during initial construction. |
| 280 LRESULT l_result = 0; | 283 LRESULT l_result = 0; |
| 281 if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param, | 284 if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param, |
| 282 &l_result)) { | 285 &l_result)) { |
| 283 return DefWindowProc(window, message, w_param, l_param); | 286 return DefWindowProc(window, message, w_param, l_param); |
| 284 } | 287 } |
| 285 return l_result; | 288 return l_result; |
| 286 } | 289 } |
| 287 | 290 |
| 288 HWND hwnd_; | 291 HWND hwnd_; |
| 292 NativeMenuWin* parent_; |
| 293 ScopedRunnableMethodFactory<MenuHostWindow> method_factory_; |
| 289 | 294 |
| 290 DISALLOW_COPY_AND_ASSIGN(MenuHostWindow); | 295 DISALLOW_COPY_AND_ASSIGN(MenuHostWindow); |
| 291 }; | 296 }; |
| 292 | 297 |
| 293 // static | 298 // static |
| 294 const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName = | 299 const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName = |
| 295 L"ViewsMenuHostWindow"; | 300 L"ViewsMenuHostWindow"; |
| 296 | 301 |
| 297 //////////////////////////////////////////////////////////////////////////////// | 302 //////////////////////////////////////////////////////////////////////////////// |
| 298 // NativeMenuWin, public: | 303 // NativeMenuWin, public: |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this); | 604 mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this); |
| 600 SetMenuInfo(menu_, &mi); | 605 SetMenuInfo(menu_, &mi); |
| 601 } | 606 } |
| 602 } | 607 } |
| 603 | 608 |
| 604 void NativeMenuWin::CreateHostWindow() { | 609 void NativeMenuWin::CreateHostWindow() { |
| 605 // This only gets called from RunMenuAt, and as such there is only ever one | 610 // This only gets called from RunMenuAt, and as such there is only ever one |
| 606 // host window per menu hierarchy, no matter how many NativeMenuWin objects | 611 // host window per menu hierarchy, no matter how many NativeMenuWin objects |
| 607 // exist wrapping submenus. | 612 // exist wrapping submenus. |
| 608 if (!host_window_.get()) | 613 if (!host_window_.get()) |
| 609 host_window_.reset(new MenuHostWindow()); | 614 host_window_.reset(new MenuHostWindow(this)); |
| 610 } | 615 } |
| 611 | 616 |
| 612 //////////////////////////////////////////////////////////////////////////////// | 617 //////////////////////////////////////////////////////////////////////////////// |
| 613 // SystemMenuModel: | 618 // SystemMenuModel: |
| 614 | 619 |
| 615 SystemMenuModel::SystemMenuModel(ui::SimpleMenuModel::Delegate* delegate) | 620 SystemMenuModel::SystemMenuModel(ui::SimpleMenuModel::Delegate* delegate) |
| 616 : SimpleMenuModel(delegate) { | 621 : SimpleMenuModel(delegate) { |
| 617 } | 622 } |
| 618 | 623 |
| 619 SystemMenuModel::~SystemMenuModel() { | 624 SystemMenuModel::~SystemMenuModel() { |
| 620 } | 625 } |
| 621 | 626 |
| 622 int SystemMenuModel::GetFirstItemIndex(gfx::NativeMenu native_menu) const { | 627 int SystemMenuModel::GetFirstItemIndex(gfx::NativeMenu native_menu) const { |
| 623 // We allow insertions before last item (Close). | 628 // We allow insertions before last item (Close). |
| 624 return std::max(0, GetMenuItemCount(native_menu) - 1); | 629 return std::max(0, GetMenuItemCount(native_menu) - 1); |
| 625 } | 630 } |
| 626 | 631 |
| 627 //////////////////////////////////////////////////////////////////////////////// | 632 //////////////////////////////////////////////////////////////////////////////// |
| 628 // MenuWrapper, public: | 633 // MenuWrapper, public: |
| 629 | 634 |
| 630 // static | 635 // static |
| 631 MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) { | 636 MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) { |
| 632 return new NativeMenuWin(menu->model(), NULL); | 637 return new NativeMenuWin(menu->model(), NULL); |
| 633 } | 638 } |
| 634 | 639 |
| 635 } // namespace views | 640 } // namespace views |
| OLD | NEW |