| Index: chrome_frame/in_place_menu.h
|
| ===================================================================
|
| --- chrome_frame/in_place_menu.h (revision 0)
|
| +++ chrome_frame/in_place_menu.h (revision 0)
|
| @@ -0,0 +1,231 @@
|
| +// Copyright 2008, Google Inc.
|
| +// All rights reserved.
|
| +//
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following disclaimer
|
| +// in the documentation and/or other materials provided with the
|
| +// distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived from
|
| +// this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#ifndef CHROME_FRAME_IN_PLACE_MENU_H_
|
| +#define CHROME_FRAME_IN_PLACE_MENU_H_
|
| +
|
| +// in_place_menu.h : menu merging implementation
|
| +//
|
| +// This file is a modified version of the menu.h file, which is
|
| +// part of the ActiveDoc MSDN sample. The modifications are largely
|
| +// conversions to Google coding guidelines. Below is the original header
|
| +// from the file.
|
| +
|
| +// This is a part of the Active Template Library.
|
| +// Copyright (c) Microsoft Corporation. All rights reserved.
|
| +//
|
| +// This source code is only intended as a supplement to the
|
| +// Active Template Library Reference and related
|
| +// electronic documentation provided with the library.
|
| +// See these sources for detailed information regarding the
|
| +// Active Template Library product.
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/scoped_comptr_win.h"
|
| +
|
| +template <class T>
|
| +class InPlaceMenu {
|
| + public:
|
| + InPlaceMenu() : shared_menu_(NULL), ole_menu_(NULL), our_menu_(NULL) {
|
| + }
|
| +
|
| + ~InPlaceMenu() {
|
| + InPlaceMenuDestroy();
|
| + }
|
| +
|
| + HRESULT InPlaceMenuCreate(LPCWSTR menu_name) {
|
| + // We might already have an in-place menu set, because we set menus
|
| + // IOleDocumentView::UIActivate as well as in
|
| + // IOleInPlaceActiveObject::OnDocWindowActivate. If we have already
|
| + // done our work, just return silently
|
| + if (ole_menu_ || shared_menu_)
|
| + return S_OK;
|
| +
|
| + ScopedComPtr<IOleInPlaceFrame> in_place_frame;
|
| + GetInPlaceFrame(in_place_frame.Receive());
|
| + // We have no IOleInPlaceFrame, no menu merging possible
|
| + if (!in_place_frame) {
|
| + NOTREACHED();
|
| + return E_FAIL;
|
| + }
|
| + // Create a blank menu and ask the container to add
|
| + // its menus into the OLEMENUGROUPWIDTHS structure
|
| + shared_menu_ = ::CreateMenu();
|
| + OLEMENUGROUPWIDTHS mgw = {0};
|
| + HRESULT hr = in_place_frame->InsertMenus(shared_menu_, &mgw);
|
| + if (FAILED(hr)) {
|
| + ::DestroyMenu(shared_menu_);
|
| + shared_menu_ = NULL;
|
| + return hr;
|
| + }
|
| + // Insert our menus
|
| + our_menu_ = LoadMenu(_AtlBaseModule.GetResourceInstance(),menu_name);
|
| + MergeMenus(shared_menu_, our_menu_, &mgw.width[0], 1);
|
| + // Send the menu to the client
|
| + ole_menu_ = (HMENU)OleCreateMenuDescriptor(shared_menu_, &mgw);
|
| + T* t = static_cast<T*>(this);
|
| + in_place_frame->SetMenu(shared_menu_, ole_menu_, t->m_hWnd);
|
| + return S_OK;
|
| + }
|
| +
|
| + HRESULT InPlaceMenuDestroy() {
|
| + ScopedComPtr<IOleInPlaceFrame> in_place_frame;
|
| + GetInPlaceFrame(in_place_frame.Receive());
|
| + if (in_place_frame) {
|
| + in_place_frame->RemoveMenus(shared_menu_);
|
| + in_place_frame->SetMenu(NULL, NULL, NULL);
|
| + }
|
| + if (ole_menu_) {
|
| + OleDestroyMenuDescriptor(ole_menu_);
|
| + ole_menu_ = NULL;
|
| + }
|
| + if (shared_menu_) {
|
| + UnmergeMenus(shared_menu_, our_menu_);
|
| + DestroyMenu(shared_menu_);
|
| + shared_menu_ = NULL;
|
| + }
|
| + if (our_menu_) {
|
| + DestroyMenu(our_menu_);
|
| + our_menu_ = NULL;
|
| + }
|
| + return S_OK;
|
| + }
|
| +
|
| + void MergeMenus(HMENU shared_menu, HMENU source_menu, LONG* menu_widths,
|
| + unsigned int width_index) {
|
| + // Copy the popups from the source menu
|
| + // Insert at appropriate spot depending on width_index
|
| + DCHECK(width_index == 0 || width_index == 1);
|
| + int position = 0;
|
| + if (width_index == 1)
|
| + position = (int)menu_widths[0];
|
| + int group_width = 0;
|
| + int menu_items = GetMenuItemCount(source_menu);
|
| + for (int index = 0; index < menu_items; index++) {
|
| + // Get the HMENU of the popup
|
| + HMENU popup_menu = ::GetSubMenu(source_menu, index);
|
| + // Separators move us to next group
|
| + UINT state = GetMenuState(source_menu, index, MF_BYPOSITION);
|
| + if (!popup_menu && (state & MF_SEPARATOR)) {
|
| + // Servers should not touch past 5
|
| + DCHECK(width_index <= 5);
|
| + menu_widths[width_index] = group_width;
|
| + group_width = 0;
|
| + if (width_index < 5)
|
| + position += static_cast<int>(menu_widths[width_index+1]);
|
| + width_index += 2;
|
| + } else {
|
| + // Get the menu item text
|
| + TCHAR item_text[256] = {0};
|
| + int text_length = GetMenuString(source_menu, index, item_text,
|
| + ARRAYSIZE(item_text), MF_BYPOSITION);
|
| + // Popups are handled differently than normal menu items
|
| + if (popup_menu) {
|
| + if (::GetMenuItemCount(popup_menu) != 0) {
|
| + // Strip the HIBYTE because it contains a count of items
|
| + state = LOBYTE(state) | MF_POPUP; // Must be popup
|
| + // Non-empty popup -- add it to the shared menu bar
|
| + InsertMenu(shared_menu, position, state|MF_BYPOSITION,
|
| + reinterpret_cast<UINT_PTR>(popup_menu), item_text);
|
| + ++position;
|
| + ++group_width;
|
| + }
|
| + } else if (text_length > 0) {
|
| + // only non-empty items are added
|
| + DCHECK(item_text[0] != 0);
|
| + // here the state does not contain a count in the HIBYTE
|
| + InsertMenu(shared_menu, position, state|MF_BYPOSITION,
|
| + GetMenuItemID(source_menu, index), item_text);
|
| + ++position;
|
| + ++group_width;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + void UnmergeMenus(HMENU shared_menu, HMENU source_menu) {
|
| + int our_item_count = GetMenuItemCount(source_menu);
|
| + int shared_item_count = GetMenuItemCount(shared_menu);
|
| +
|
| + for (int index = shared_item_count - 1; index >= 0; index--) {
|
| + // Check the popup menus
|
| + HMENU popup_menu = ::GetSubMenu(shared_menu, index);
|
| + if (popup_menu) {
|
| + // If it is one of ours, remove it from the shared menu
|
| + for (int sub_index = 0; sub_index < our_item_count; sub_index++) {
|
| + if (::GetSubMenu(source_menu, sub_index) == popup_menu) {
|
| + // Remove the menu from hMenuShared
|
| + RemoveMenu(shared_menu, index, MF_BYPOSITION);
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + protected:
|
| + HRESULT GetInPlaceFrame(IOleInPlaceFrame** in_place_frame) {
|
| + if (!in_place_frame) {
|
| + NOTREACHED();
|
| + return E_POINTER;
|
| + }
|
| + T* t = static_cast<T*>(this);
|
| + HRESULT hr = E_FAIL;
|
| + if (!t->in_place_frame_) {
|
| + // We weren't given an IOleInPlaceFrame pointer, so
|
| + // we'll have to get it ourselves.
|
| + if (t->m_spInPlaceSite) {
|
| + t->frame_info_.cb = sizeof(OLEINPLACEFRAMEINFO);
|
| + ScopedComPtr<IOleInPlaceUIWindow> in_place_ui_window;
|
| + RECT position_rect = {0};
|
| + RECT clip_rect = {0};
|
| + hr = t->m_spInPlaceSite->GetWindowContext(in_place_frame,
|
| + in_place_ui_window.Receive(),
|
| + &position_rect, &clip_rect,
|
| + &t->frame_info_);
|
| + }
|
| + } else {
|
| + *in_place_frame = t->in_place_frame_;
|
| + (*in_place_frame)->AddRef();
|
| + hr = S_OK;
|
| + }
|
| + return hr;
|
| + }
|
| +
|
| + protected:
|
| + // The OLE menu descriptor created by the OleCreateMenuDescriptor
|
| + HMENU ole_menu_;
|
| + // The shared menu that we pass to IOleInPlaceFrame::SetMenu
|
| + HMENU shared_menu_;
|
| + // Our menu resource that we want to insert
|
| + HMENU our_menu_;
|
| +};
|
| +
|
| +#endif // CHROME_FRAME_IN_PLACE_MENU_H_
|
| +
|
|
|