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 |