diff options
author | slightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 05:11:58 +0000 |
---|---|---|
committer | slightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 05:11:58 +0000 |
commit | f781782dd67077478e117c61dca4ea5eefce3544 (patch) | |
tree | 4801f724123cfdcbb69c4e7fe40a565b331723ae /chrome_frame/in_place_menu.h | |
parent | 63cf4759efa2373e33436fb5df6849f930081226 (diff) | |
download | chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.zip chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.gz chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.bz2 |
Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming in a separate CL.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/218019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27042 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/in_place_menu.h')
-rw-r--r-- | chrome_frame/in_place_menu.h | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/chrome_frame/in_place_menu.h b/chrome_frame/in_place_menu.h new file mode 100644 index 0000000..9742896 --- /dev/null +++ b/chrome_frame/in_place_menu.h @@ -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_ + |