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_ |
+ |