1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CEF_LIBCEF_BROWSER_NATIVE_NATIVE_MENU_WIN_H_ 6 #define CEF_LIBCEF_BROWSER_NATIVE_NATIVE_MENU_WIN_H_ 7 8 #include <memory> 9 #include <vector> 10 11 #include "libcef/browser/native/menu_wrapper.h" 12 13 #include "base/compiler_specific.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/observer_list.h" 16 17 namespace ui { 18 class MenuModel; 19 } 20 21 namespace views { 22 23 // A Windows implementation of MenuWrapper. 24 // TODO(beng): rename to MenuWin once the old class is dead. 25 class CefNativeMenuWin : public MenuWrapper { 26 public: 27 // Construct a CefNativeMenuWin, with a model and delegate. If 28 // |system_menu_for| is non-NULL, the CefNativeMenuWin wraps the system menu 29 // for that window. 30 // The caller owns the model and the delegate. 31 CefNativeMenuWin(ui::MenuModel* model, HWND system_menu_for); 32 33 CefNativeMenuWin(const CefNativeMenuWin&) = delete; 34 CefNativeMenuWin& operator=(const CefNativeMenuWin&) = delete; 35 36 ~CefNativeMenuWin() override; 37 38 // Overridden from MenuWrapper: 39 void RunMenuAt(const gfx::Point& point, int alignment) override; 40 void CancelMenu() override; 41 void Rebuild(MenuInsertionDelegateWin* delegate) override; 42 void UpdateStates() override; 43 HMENU GetNativeMenu() const override; 44 MenuAction GetMenuAction() const override; 45 void SetMinimumWidth(int width) override; 46 47 private: 48 // IMPORTANT: Note about indices. 49 // Functions in this class deal in two index spaces: 50 // 1. menu_index - the index of an item within the actual Windows 51 // native menu. 52 // 2. model_index - the index of the item within our model. 53 // These two are most often but not always the same value! The 54 // notable exception is when this object is used to wrap the 55 // Windows System Menu. In this instance, the model indices start 56 // at 0, but the insertion index into the existing menu is not. 57 // It is important to take this into consideration when editing the 58 // code in the functions in this class. 59 60 struct HighlightedMenuItemInfo; 61 62 // Returns true if the item at the specified index is a separator. 63 bool IsSeparatorItemAt(int menu_index) const; 64 65 // Add items. See note above about indices. 66 void AddMenuItemAt(int menu_index, int model_index); 67 void AddSeparatorItemAt(int menu_index, int model_index); 68 69 // Sets the state of the item at the specified index. 70 void SetMenuItemState(int menu_index, 71 bool enabled, 72 bool checked, 73 bool is_default); 74 75 // Sets the label of the item at the specified index. 76 void SetMenuItemLabel(int menu_index, 77 int model_index, 78 const std::wstring& label); 79 80 // Updates the local data structure with the correctly formatted version of 81 // |label| at the specified model_index, and adds string data to |mii| if 82 // the menu is not owner-draw. That's a mouthful. This function exists because 83 // of the peculiarities of the Windows menu API. 84 void UpdateMenuItemInfoForString(MENUITEMINFO* mii, 85 int model_index, 86 const std::wstring& label); 87 88 // Returns the alignment flags to be passed to TrackPopupMenuEx, based on the 89 // supplied alignment and the UI text direction. 90 UINT GetAlignmentFlags(int alignment) const; 91 92 // Resets the native menu stored in |menu_| by destroying any old menu then 93 // creating a new empty one. 94 void ResetNativeMenu(); 95 96 // Creates the host window that receives notifications from the menu. 97 void CreateHostWindow(); 98 99 // Callback from task to notify menu it was selected. 100 void DelayedSelect(); 101 102 // Given a menu that's currently popped-up, find the currently highlighted 103 // item. Returns true if a highlighted item was found. 104 static bool GetHighlightedMenuItemInfo(HMENU menu, 105 HighlightedMenuItemInfo* info); 106 107 // Hook to receive keyboard events while the menu is open. 108 static LRESULT CALLBACK MenuMessageHook(int n_code, 109 WPARAM w_param, 110 LPARAM l_param); 111 112 // Our attached model and delegate. 113 ui::MenuModel* model_; 114 115 HMENU menu_; 116 117 // True if the contents of menu items in this menu are drawn by the menu host 118 // window, rather than Windows. 119 bool owner_draw_; 120 121 // An object that collects all of the data associated with an individual menu 122 // item. 123 struct ItemData; 124 using ItemDataList = std::vector<std::unique_ptr<ItemData>>; 125 ItemDataList items_; 126 127 // The window that receives notifications from the menu. 128 class MenuHostWindow; 129 friend MenuHostWindow; 130 std::unique_ptr<MenuHostWindow> host_window_; 131 132 // The HWND this menu is the system menu for, or NULL if the menu is not a 133 // system menu. 134 HWND system_menu_for_; 135 136 // The index of the first item in the model in the menu. 137 int first_item_index_; 138 139 // The action that took place during the call to RunMenuAt. 140 MenuAction menu_action_; 141 142 // See comment in MenuMessageHook for details on these. 143 CefNativeMenuWin* menu_to_select_; 144 int position_to_select_; 145 146 // If we're a submenu, this is our parent. 147 CefNativeMenuWin* parent_; 148 149 // If non-null the destructor sets this to true. This is set to non-null while 150 // the menu is showing. It is used to detect if the menu was deleted while 151 // running. 152 bool* destroyed_flag_; 153 154 base::WeakPtrFactory<CefNativeMenuWin> menu_to_select_factory_; 155 156 // Ugly: a static pointer to the instance of this class that currently 157 // has a menu open, because our hook function that receives keyboard 158 // events doesn't have a mechanism to get a user data pointer. 159 static CefNativeMenuWin* open_native_menu_win_; 160 }; 161 162 } // namespace views 163 164 #endif // CEF_LIBCEF_BROWSER_NATIVE_NATIVE_MENU_WIN_H_ 165