diff options
author | rhashimoto@chromium.org <rhashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-12 16:54:12 +0000 |
---|---|---|
committer | rhashimoto@chromium.org <rhashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-12 16:54:12 +0000 |
commit | b516e2d2ff5ad3d2a7c754b081566137fd7ed089 (patch) | |
tree | 75d5a32b65ce6b417eba6ff42fe0dbe3d1d8c5b1 | |
parent | 471072f9fd132a46b24ddd159922f6a4d099707d (diff) | |
download | chromium_src-b516e2d2ff5ad3d2a7c754b081566137fd7ed089.zip chromium_src-b516e2d2ff5ad3d2a7c754b081566137fd7ed089.tar.gz chromium_src-b516e2d2ff5ad3d2a7c754b081566137fd7ed089.tar.bz2 |
Convert RenderViewContextMenu to MenuItemView.
This CL is part of general GTK removal for ChromiumOS. Menu2 uses GTK on linux so we are replacing it with MenuItemView. Chrome Frame currently passes the context menu between processes by using the HMENU. Because MenuItemView does not use HMENU, we need to use another mechanism.
This CL creates a ContextMenuModel struct that is serialized into an automation message for Chrome Frame. ContextMenuModel contains the context menu definition in-band replacing the out-of-band HMENU.
BUG=chromium-os:13887
TEST=none
Review URL: http://codereview.chromium.org/7167002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92182 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/external_tab_container_win.cc | 36 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_context_menu.h | 3 | ||||
-rw-r--r-- | chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc | 30 | ||||
-rw-r--r-- | chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h | 13 | ||||
-rw-r--r-- | chrome/common/automation_messages.cc | 98 | ||||
-rw-r--r-- | chrome/common/automation_messages.h | 47 | ||||
-rw-r--r-- | chrome/common/automation_messages_internal.h | 2 | ||||
-rw-r--r-- | chrome_frame/cfproxy.h | 1 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_activex_base.h | 4 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_delegate.h | 4 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_plugin.h | 17 | ||||
-rw-r--r-- | chrome_frame/external_tab.cc | 5 | ||||
-rw-r--r-- | chrome_frame/external_tab.h | 6 | ||||
-rw-r--r-- | chrome_frame/external_tab_test.cc | 4 | ||||
-rw-r--r-- | chrome_frame/utils.cc | 97 | ||||
-rw-r--r-- | chrome_frame/utils.h | 6 |
16 files changed, 277 insertions, 96 deletions
diff --git a/chrome/browser/external_tab_container_win.cc b/chrome/browser/external_tab_container_win.cc index 2245494..09d4593 100644 --- a/chrome/browser/external_tab_container_win.cc +++ b/chrome/browser/external_tab_container_win.cc @@ -54,12 +54,43 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/view_prop.h" +#include "ui/base/models/menu_model.h" #include "views/layout/grid_layout.h" using ui::ViewProp; static const char kWindowObjectKey[] = "ChromeWindowObject"; +namespace { + +// Convert ui::MenuModel into a serializable form for Chrome Frame +ContextMenuModel* ConvertMenuModel(const ui::MenuModel* ui_model) { + ContextMenuModel* new_model = new ContextMenuModel; + + const int index_base = ui_model->GetFirstItemIndex(NULL); + const int item_count = ui_model->GetItemCount(); + new_model->items.reserve(item_count); + for (int i = 0; i < item_count; ++i) { + const int index = index_base + i; + if (ui_model->IsVisibleAt(index)) { + ContextMenuModel::Item item; + item.type = ui_model->GetTypeAt(index); + item.item_id = ui_model->GetCommandIdAt(index); + item.label = ui_model->GetLabelAt(index); + item.checked = ui_model->IsItemCheckedAt(index); + item.enabled = ui_model->IsEnabledAt(index); + if (item.type == ui::MenuModel::TYPE_SUBMENU) + item.submenu = ConvertMenuModel(ui_model->GetSubmenuModelAt(index)); + + new_model->items.push_back(item); + } + } + + return new_model; +} + +} // namespace + // This class overrides the LinkClicked function in the PageInfoBubbleView // class and routes the help center link navigation to the host browser. class ExternalTabPageInfoBubbleView : public PageInfoBubbleView { @@ -596,6 +627,9 @@ bool ExternalTabContainer::HandleContextMenu(const ContextMenuParams& params) { external_context_menu_->Init(); external_context_menu_->UpdateMenuItemStates(); + scoped_ptr<ContextMenuModel> context_menu_model( + ConvertMenuModel(&external_context_menu_->menu_model())); + POINT screen_pt = { params.x, params.y }; MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_pt, 1); @@ -612,7 +646,7 @@ bool ExternalTabContainer::HandleContextMenu(const ContextMenuParams& params) { bool rtl = base::i18n::IsRTL(); automation_->Send( new AutomationMsg_ForwardContextMenuToExternalHost(tab_handle_, - external_context_menu_->GetMenuHandle(), + *context_menu_model, rtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN, ipc_params)); return true; diff --git a/chrome/browser/tab_contents/render_view_context_menu.h b/chrome/browser/tab_contents/render_view_context_menu.h index 39b2df8..f5f600c 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.h +++ b/chrome/browser/tab_contents/render_view_context_menu.h @@ -45,6 +45,9 @@ class RenderViewContextMenu : public ui::SimpleMenuModel::Delegate { // Initializes the context menu. void Init(); + // Provide access to the menu model for ExternalTabContainer. + const ui::MenuModel& menu_model() const { return menu_model_; } + // SimpleMenuModel::Delegate implementation. virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; diff --git a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc index e03d7eb0..577db98 100644 --- a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc +++ b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.cc @@ -8,10 +8,12 @@ #include "chrome/app/chrome_command_ids.h" #include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/tab_contents.h" +#include "content/browser/tab_contents/tab_contents_view.h" #include "grit/generated_resources.h" #include "ui/base/keycodes/keyboard_codes.h" #include "views/accelerator.h" -#include "views/controls/menu/menu_2.h" +#include "views/controls/menu/menu_item_view.h" +#include "views/controls/menu/menu_model_adapter.h" //////////////////////////////////////////////////////////////////////////////// // RenderViewContextMenuViews, public: @@ -26,7 +28,9 @@ RenderViewContextMenuViews::~RenderViewContextMenuViews() { } void RenderViewContextMenuViews::RunMenuAt(int x, int y) { - menu_->RunContextMenuAt(gfx::Point(x, y)); + menu_->RunMenuAt(source_tab_contents_->view()->GetTopLevelNativeWindow(), + NULL, gfx::Rect(gfx::Point(x, y), gfx::Size()), + views::MenuItemView::TOPLEFT, true); } #if defined(OS_WIN) @@ -36,30 +40,16 @@ void RenderViewContextMenuViews::SetExternal() { #endif void RenderViewContextMenuViews::UpdateMenuItemStates() { - menu_->UpdateStates(); + menu_delegate_->BuildMenu(menu_.get()); } //////////////////////////////////////////////////////////////////////////////// // RenderViewContextMenuViews, protected: void RenderViewContextMenuViews::PlatformInit() { - menu_.reset(new views::Menu2(&menu_model_)); - -#if defined(OS_WIN) - if (external_) { - // The external tab container needs to be notified by command - // and not by index. So we are turning off the MNS_NOTIFYBYPOS - // style. - HMENU menu = GetMenuHandle(); - DCHECK(menu != NULL); - - MENUINFO mi = {0}; - mi.cbSize = sizeof(mi); - mi.fMask = MIM_STYLE | MIM_MENUDATA; - mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this); - SetMenuInfo(menu, &mi); - } -#endif + menu_delegate_.reset(new views::MenuModelAdapter(&menu_model_)); + menu_.reset(new views::MenuItemView(menu_delegate_.get())); + UpdateMenuItemStates(); } bool RenderViewContextMenuViews::GetAcceleratorForCommandId( diff --git a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h index 5b74407..2daa957 100644 --- a/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h +++ b/chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h @@ -9,7 +9,11 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "chrome/browser/tab_contents/render_view_context_menu.h" -#include "views/controls/menu/menu_2.h" + +namespace views { +class MenuItemView; +class MenuModelAdapter; +} // namespace views class RenderViewContextMenuViews : public RenderViewContextMenu { public: @@ -20,10 +24,6 @@ class RenderViewContextMenuViews : public RenderViewContextMenu { void RunMenuAt(int x, int y); - gfx::NativeMenu GetMenuHandle() const { - return (menu_.get() ? menu_->GetNativeMenu() : NULL); - } - #if defined(OS_WIN) // Set this menu to show for an external tab contents. This // only has an effect before Init() is called. @@ -39,7 +39,8 @@ class RenderViewContextMenuViews : public RenderViewContextMenu { ui::Accelerator* accelerator); private: // The context menu itself and its contents. - scoped_ptr<views::Menu2> menu_; + scoped_ptr<views::MenuModelAdapter> menu_delegate_; + scoped_ptr<views::MenuItemView> menu_; DISALLOW_COPY_AND_ASSIGN(RenderViewContextMenuViews); }; diff --git a/chrome/common/automation_messages.cc b/chrome/common/automation_messages.cc index 87a294b..39420cd 100644 --- a/chrome/common/automation_messages.cc +++ b/chrome/common/automation_messages.cc @@ -4,6 +4,7 @@ #include "chrome/common/common_param_traits.h" #include "content/common/common_param_traits.h" +#include "ui/base/models/menu_model.h" #define IPC_MESSAGE_IMPL #include "chrome/common/automation_messages.h" @@ -148,6 +149,22 @@ MiniContextMenuParams::MiniContextMenuParams(int in_screen_x, MiniContextMenuParams::~MiniContextMenuParams() {} +ContextMenuModel::ContextMenuModel() { +} + +ContextMenuModel::~ContextMenuModel() { + for (size_t i = 0; i < items.size(); ++i) + delete items[i].submenu; +} + +ContextMenuModel::Item::Item() + : type(static_cast<int>(ui::MenuModel::TYPE_COMMAND)), + item_id(0), + checked(false), + enabled(true), + submenu(NULL) { +} + AttachExternalTabParams::AttachExternalTabParams() : cookie(0), disposition(0), @@ -644,6 +661,87 @@ void ParamTraits<MiniContextMenuParams>::Log(const param_type& p, } // static +void ParamTraits<ContextMenuModel>::Write(Message* m, + const param_type& p) { + WriteParam(m, p.items.size()); + for (size_t i = 0; i < p.items.size(); ++i) { + WriteParam(m, static_cast<int>(p.items[i].type)); + WriteParam(m, p.items[i].item_id); + WriteParam(m, p.items[i].label); + WriteParam(m, p.items[i].checked); + WriteParam(m, p.items[i].enabled); + + if (p.items[i].type == static_cast<int>(ui::MenuModel::TYPE_SUBMENU)) { + Write(m, *p.items[i].submenu); + } + } +} + +// static +bool ParamTraits<ContextMenuModel>::Read(const Message* m, + void** iter, + param_type* p) { + size_t item_count = 0; + if (!ReadParam(m, iter, &item_count)) + return false; + + p->items.reserve(item_count); + for (size_t i = 0; i < item_count; ++i) { + ContextMenuModel::Item item; + if (!ReadParam(m, iter, &item.type)) + return false; + if (!ReadParam(m, iter, &item.item_id)) + return false; + if (!ReadParam(m, iter, &item.label)) + return false; + if (!ReadParam(m, iter, &item.checked)) + return false; + if (!ReadParam(m, iter, &item.enabled)) + return false; + + if (item.type == static_cast<int>(ui::MenuModel::TYPE_SUBMENU)) { + item.submenu = new ContextMenuModel; + if (!Read(m, iter, item.submenu)) { + delete item.submenu; + item.submenu = NULL; + return false; + } + } + + p->items.push_back(item); + } + + return true; +} + +// static +void ParamTraits<ContextMenuModel>::Log(const param_type& p, + std::string* l) { + l->append("("); + for (size_t i = 0; i < p.items.size(); ++i) { + const ContextMenuModel::Item& item = p.items[i]; + if (i) + l->append(", "); + l->append("("); + LogParam(item.type, l); + l->append(", "); + LogParam(item.item_id, l); + l->append(", "); + LogParam(item.label, l); + l->append(", "); + LogParam(item.checked, l); + l->append(", "); + LogParam(item.enabled, l); + if (item.type == ui::MenuModel::TYPE_SUBMENU) { + l->append(", "); + Log(*item.submenu, l); + } + l->append(")"); + } + l->append(")"); +} + +// static void ParamTraits<AttachExternalTabParams>::Write(Message* m, const param_type& p) { WriteParam(m, p.cookie); diff --git a/chrome/common/automation_messages.h b/chrome/common/automation_messages.h index e714c45..91ec439 100644 --- a/chrome/common/automation_messages.h +++ b/chrome/common/automation_messages.h @@ -4,8 +4,10 @@ // Multiply-included message file, no traditional include guard. #include <string> +#include <vector> #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "chrome/common/automation_constants.h" #include "chrome/common/content_settings.h" #include "content/common/common_param_traits.h" @@ -153,6 +155,42 @@ struct MiniContextMenuParams { GURL frame_url; }; +// This struct passes information about the context menu in Chrome stored +// as a ui::MenuModel to Chrome Frame. It is basically a container of +// items that go in the menu. An item may be a submenu, so the data +// structure may be a tree. +struct ContextMenuModel { + ContextMenuModel(); + ~ContextMenuModel(); + + // This struct describes one item in the menu. + struct Item { + Item(); + + // This is the type of the menu item, using values from the enum + // ui::MenuModel::ItemType (serialized as an int). + int type; + + // This is the command id of the menu item, which will be passed by + // Chrome Frame to Chrome if the item is selected. + int item_id; + + // This the the menu label, if needed. + std::wstring label; + + // These are states of the menu item. + bool checked; + bool enabled; + + // This recursively describes the submenu if type is + // ui::MenuModel::TYPE_SUBMENU. + ContextMenuModel* submenu; + }; + + // This is the list of menu items. + std::vector<Item> items; +}; + struct AttachExternalTabParams { AttachExternalTabParams(); AttachExternalTabParams(uint64 cookie, @@ -354,6 +392,15 @@ struct ParamTraits<MiniContextMenuParams> { static void Log(const param_type& p, std::string* l); }; +// Traits for ContextMenuModel structure to pack/unpack. +template <> +struct ParamTraits<ContextMenuModel> { + typedef ContextMenuModel param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; + template <> struct ParamTraits<AttachExternalTabParams> { typedef AttachExternalTabParams param_type; diff --git a/chrome/common/automation_messages_internal.h b/chrome/common/automation_messages_internal.h index 7f959e2..4502a24 100644 --- a/chrome/common/automation_messages_internal.h +++ b/chrome/common/automation_messages_internal.h @@ -927,7 +927,7 @@ IPC_SYNC_MESSAGE_CONTROL0_1(AutomationMsg_GetBrowserLocale, #if defined(OS_WIN) IPC_MESSAGE_ROUTED3(AutomationMsg_ForwardContextMenuToExternalHost, - HANDLE /* source menu handle */, + ContextMenuModel /* description of menu */, int /* align flags */, MiniContextMenuParams /* params */) diff --git a/chrome_frame/cfproxy.h b/chrome_frame/cfproxy.h index 7e4c0fb..6bc8abd 100644 --- a/chrome_frame/cfproxy.h +++ b/chrome_frame/cfproxy.h @@ -22,6 +22,7 @@ class ChromeProxyFactory; class GURL; struct AttachExternalTabParams; struct AutomationURLRequest; +struct ContextMenuModel; struct ExternalTabSettings; struct MiniContextMenuParams; struct NavigationInfo; diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h index fce6164..46287fd7 100644 --- a/chrome_frame/chrome_frame_activex_base.h +++ b/chrome_frame/chrome_frame_activex_base.h @@ -504,11 +504,11 @@ END_MSG_MAP() HostNavigate(GURL(url), GURL(), chrome_frame::GetDisposition(params)); } - virtual void OnHandleContextMenu(HANDLE menu_handle, + virtual void OnHandleContextMenu(const ContextMenuModel& menu_model, int align_flags, const MiniContextMenuParams& params) { scoped_refptr<BasePlugin> ref(this); - ChromeFramePlugin<T>::OnHandleContextMenu(menu_handle, align_flags, params); + ChromeFramePlugin<T>::OnHandleContextMenu(menu_model, align_flags, params); } LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam, diff --git a/chrome_frame/chrome_frame_delegate.h b/chrome_frame/chrome_frame_delegate.h index 3af3bd4..582365b 100644 --- a/chrome_frame/chrome_frame_delegate.h +++ b/chrome_frame/chrome_frame_delegate.h @@ -21,6 +21,7 @@ class GURL; struct AttachExternalTabParams; struct AutomationURLRequest; +struct ContextMenuModel; struct MiniContextMenuParams; struct NavigationInfo; @@ -105,7 +106,8 @@ class ChromeFrameDelegateImpl : public ChromeFrameDelegate { virtual void OnMessageFromChromeFrame(const std::string& message, const std::string& origin, const std::string& target) {} - virtual void OnHandleContextMenu(HANDLE menu_handle, int align_flags, + virtual void OnHandleContextMenu(const ContextMenuModel& context_menu_model, + int align_flags, const MiniContextMenuParams& params) {} virtual void OnRequestStart( int request_id, const AutomationURLRequest& request) {} diff --git a/chrome_frame/chrome_frame_plugin.h b/chrome_frame/chrome_frame_plugin.h index af4242a..51106ab 100644 --- a/chrome_frame/chrome_frame_plugin.h +++ b/chrome_frame/chrome_frame_plugin.h @@ -120,23 +120,20 @@ END_MSG_MAP() OnLoadFailed(error_code, gurl.spec()); } - virtual void OnHandleContextMenu(HANDLE menu_handle, + virtual void OnHandleContextMenu(const ContextMenuModel& menu_model, int align_flags, const MiniContextMenuParams& params) { - if (!menu_handle || !automation_client_.get()) { + if (!automation_client_.get()) { NOTREACHED(); return; } - // TrackPopupMenuEx call will fail on IE on Vista running - // in low integrity mode. We DO seem to be able to enumerate the menu - // though, so just clone it and show the copy: - HMENU copy = UtilCloneContextMenu(static_cast<HMENU>(menu_handle)); - if (!copy) + HMENU menu = BuildContextMenu(menu_model); + if (!menu) return; T* self = static_cast<T*>(this); - if (self->PreProcessContextMenu(copy)) { + if (self->PreProcessContextMenu(menu)) { // In order for the context menu to handle keyboard input, give the // ActiveX window focus. ignore_setfocus_ = true; @@ -145,7 +142,7 @@ END_MSG_MAP() UINT flags = align_flags | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE; int x, y; ChromeFramePluginGetParamsCoordinates(params, &x, &y); - UINT selected = TrackPopupMenuEx(copy, flags, x, y, GetWindow(), NULL); + UINT selected = TrackPopupMenuEx(menu, flags, x, y, GetWindow(), NULL); // Menu is over now give focus back to chrome GiveFocusToChrome(false); if (IsValid() && selected != 0 && @@ -154,7 +151,7 @@ END_MSG_MAP() } } - DestroyMenu(copy); + DestroyMenu(menu); } LRESULT OnSetFocus(UINT message, WPARAM wparam, LPARAM lparam, diff --git a/chrome_frame/external_tab.cc b/chrome_frame/external_tab.cc index c9eb204..6be47a7 100644 --- a/chrome_frame/external_tab.cc +++ b/chrome_frame/external_tab.cc @@ -282,11 +282,12 @@ void ExternalTabProxy::OnHandleAccelerator(const MSG& accel_message) { } void ExternalTabProxy::OnHandleContextMenu( - HANDLE menu_handle, + const ContextMenuModel& context_menu_model, int align_flags, const MiniContextMenuParams& params) { ui_.PostTask(FROM_HERE, NewRunnableMethod(ui_delegate_, - &UIDelegate::OnHandleContextMenu, menu_handle, align_flags, params)); + &UIDelegate::OnHandleContextMenu, context_menu_model, align_flags, + params)); } void ExternalTabProxy::OnTabbedOut(bool reverse) { diff --git a/chrome_frame/external_tab.h b/chrome_frame/external_tab.h index 66844df07..26abf8f 100644 --- a/chrome_frame/external_tab.h +++ b/chrome_frame/external_tab.h @@ -32,7 +32,6 @@ class WaitableEvent; namespace IPC { struct NavigationInfo; -struct MiniContextMenuParams; } namespace gfx { @@ -54,7 +53,7 @@ class UIDelegate { const std::string& message, const std::string& origin, const std::string& target) = 0; virtual void OnHandleContextMenu( - HANDLE menu_handle, int align_flags, + const ContextMenuModel& context_menu_model, int align_flags, const MiniContextMenuParams& params) = 0; virtual void OnHandleAccelerator(const MSG& accel_message) = 0; virtual void OnTabbedOut(bool reverse) = 0; @@ -168,7 +167,8 @@ class ExternalTabProxy : public CWindowImpl<ExternalTabProxy>, // Misc. UI. virtual void OnHandleAccelerator(const MSG& accel_message); - virtual void OnHandleContextMenu(HANDLE menu_handle, int align_flags, + virtual void OnHandleContextMenu(const ContextMenuModel& context_menu_model, + int align_flags, const MiniContextMenuParams& params); virtual void OnTabbedOut(bool reverse); diff --git a/chrome_frame/external_tab_test.cc b/chrome_frame/external_tab_test.cc index 46da607..63834a0 100644 --- a/chrome_frame/external_tab_test.cc +++ b/chrome_frame/external_tab_test.cc @@ -40,8 +40,8 @@ struct MockUIDelegate : public UIDelegate { MOCK_METHOD1(OnMoveWindow, void(const gfx::Rect& pos)); MOCK_METHOD3(OnMessageFromChromeFrame, void(const std::string& message, const std::string& origin, const std::string& target)); - MOCK_METHOD3(OnHandleContextMenu, void(HANDLE menu_handle, int align_flags, - const MiniContextMenuParams& params)); + MOCK_METHOD3(OnHandleContextMenu, void(const ContextMenuModel& menu_model, + int align_flags, const MiniContextMenuParams& params)); MOCK_METHOD1(OnHandleAccelerator, void(const MSG& accel_message)); MOCK_METHOD1(OnTabbedOut, void(bool reverse)); MOCK_METHOD1(OnGoToHistoryOffset, void(int offset)); diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc index a55d858..b80511e 100644 --- a/chrome_frame/utils.cc +++ b/chrome_frame/utils.cc @@ -25,6 +25,7 @@ #include "base/win/scoped_bstr.h" #include "base/win/scoped_comptr.h" #include "base/win/scoped_variant.h" +#include "chrome/common/automation_messages.h" #include "chrome/common/chrome_paths_internal.h" #include "chrome/common/url_constants.h" #include "chrome/installer/util/chrome_frame_distribution.h" @@ -38,6 +39,7 @@ #include "grit/chromium_strings.h" #include "net/base/escape.h" #include "net/http/http_util.h" +#include "ui/base/models/menu_model.h" #include "chrome_tab.h" // NOLINT @@ -542,61 +544,66 @@ namespace { const int kMaxSubmenuDepth = 10; -// Copies original_menu and returns the copy. The caller is responsible for -// closing the returned HMENU. This does not currently copy over bitmaps -// (e.g. hbmpChecked, hbmpUnchecked or hbmpItem), so checkmarks, radio buttons, -// and custom icons won't work. +// Builds a Windows menu from the menu model sent from Chrome. The +// caller is responsible for closing the returned HMENU. This does +// not currently handle bitmaps (e.g. hbmpChecked, hbmpUnchecked or +// hbmpItem), so checkmarks, radio buttons, and custom icons won't work. // It also copies over submenus up to a maximum depth of kMaxSubMenuDepth. -// -// TODO(robertshield): Add support for the bitmap fields if need be. -HMENU UtilCloneContextMenuImpl(HMENU original_menu, int depth) { - DCHECK(IsMenu(original_menu)); - +HMENU BuildContextMenuImpl(const ContextMenuModel* menu_model, int depth) { if (depth >= kMaxSubmenuDepth) return NULL; - HMENU new_menu = CreatePopupMenu(); - int item_count = GetMenuItemCount(original_menu); - if (item_count <= 0) { - NOTREACHED(); - } else { - for (int i = 0; i < item_count; i++) { - MENUITEMINFO item_info = { 0 }; - item_info.cbSize = sizeof(MENUITEMINFO); - item_info.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE | - MIIM_STATE | MIIM_DATA | MIIM_SUBMENU | - MIIM_CHECKMARKS | MIIM_BITMAP; - - // Call GetMenuItemInfo a first time to obtain the buffer size for - // the label. - if (GetMenuItemInfo(original_menu, i, TRUE, &item_info)) { - item_info.cch++; // Increment this as per MSDN - std::vector<wchar_t> buffer(item_info.cch, 0); - item_info.dwTypeData = &buffer[0]; - - // Call GetMenuItemInfo a second time with dwTypeData set to a buffer - // of a correct size to get the label. - GetMenuItemInfo(original_menu, i, TRUE, &item_info); - - // Clone any submenus. Within reason. - if (item_info.hSubMenu) { - HMENU new_submenu = UtilCloneContextMenuImpl(item_info.hSubMenu, - depth + 1); - item_info.hSubMenu = new_submenu; - } - - // Now insert the item into the new menu. - InsertMenuItem(new_menu, i, TRUE, &item_info); - } + HMENU menu = CreatePopupMenu(); + for (size_t i = 0; i < menu_model->items.size(); i++) { + const ContextMenuModel::Item& item = menu_model->items[i]; + + MENUITEMINFO item_info = { 0 }; + item_info.cbSize = sizeof(MENUITEMINFO); + switch (item.type) { + case ui::MenuModel::TYPE_COMMAND: + case ui::MenuModel::TYPE_CHECK: + item_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; + item_info.fType = MFT_STRING; + item_info.wID = item.item_id; + item_info.dwTypeData = const_cast<LPWSTR>(item.label.c_str()); + break; + case ui::MenuModel::TYPE_RADIO: + item_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING; + item_info.fType = MFT_STRING | MFT_RADIOCHECK; + item_info.wID = item.item_id; + item_info.dwTypeData = const_cast<LPWSTR>(item.label.c_str()); + break; + case ui::MenuModel::TYPE_SEPARATOR: + item_info.fMask = MIIM_FTYPE; + item_info.fType = MFT_SEPARATOR; + break; + case ui::MenuModel::TYPE_SUBMENU: + item_info.fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_SUBMENU; + item_info.fType = MFT_STRING; + item_info.wID = item.item_id; + item_info.dwTypeData = const_cast<LPWSTR>(item.label.c_str()); + item_info.hSubMenu = BuildContextMenuImpl(item.submenu, depth + 1); + break; + default: + NOTREACHED() << "Unsupported MenuModel::ItemType " << item.type; + break; } + + item_info.fMask |= MIIM_STATE; + item_info.fState = + (item.checked ? MFS_CHECKED : MFS_UNCHECKED) | + (item.enabled ? MFS_ENABLED : (MFS_DISABLED | MFS_GRAYED)); + + InsertMenuItem(menu, i, TRUE, &item_info); } - return new_menu; + + return menu; } } // namespace -HMENU UtilCloneContextMenu(HMENU original_menu) { - return UtilCloneContextMenuImpl(original_menu, 0); +HMENU BuildContextMenu(const ContextMenuModel& menu_model) { + return BuildContextMenuImpl(&menu_model, 0); } std::string ResolveURL(const std::string& document, diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h index 7c24e9e..a41978e 100644 --- a/chrome_frame/utils.h +++ b/chrome_frame/utils.h @@ -23,6 +23,7 @@ class FilePath; interface IBrowserService; interface IWebBrowser2; +struct ContextMenuModel; // utils.h : Various utility functions and classes @@ -225,9 +226,8 @@ bool IsIEInPrivate(); // Calls [ieframe|shdocvw]!DoFileDownload to initiate a download. HRESULT DoFileDownloadInIE(const wchar_t* url); -// Creates a copy of a menu. We need this when original menu comes from -// a process with higher integrity. -HMENU UtilCloneContextMenu(HMENU original_menu); +// Construct a menu from the model sent from Chrome. +HMENU BuildContextMenu(const ContextMenuModel& menu_model); // Uses GURL internally to append 'relative' to 'document' std::string ResolveURL(const std::string& document, |