diff options
author | twiz@chromium.org <twiz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-16 02:24:18 +0000 |
---|---|---|
committer | twiz@chromium.org <twiz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-16 02:24:18 +0000 |
commit | 2b19e2feeac2a01b2068595bd2913a194a6527e5 (patch) | |
tree | fff83de7ba198462e1d00b96911685418dd130bd | |
parent | 00a3768102287ae6f8ff5e28347a920759d3374d (diff) | |
download | chromium_src-2b19e2feeac2a01b2068595bd2913a194a6527e5.zip chromium_src-2b19e2feeac2a01b2068595bd2913a194a6527e5.tar.gz chromium_src-2b19e2feeac2a01b2068595bd2913a194a6527e5.tar.bz2 |
Clone of issue 600130. (http://codereview.chromium.org/600130)
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/593111
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39077 0039d316-1c4b-4281-b951-d872f2087c98
22 files changed, 332 insertions, 50 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 8cef80a..be3a44e 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -465,6 +465,9 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(AutomationMsg_ShutdownSessionService, ShutdownSessionService) IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync) +#if defined(OS_WIN) + IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved) +#endif IPC_END_MESSAGE_MAP() } @@ -2264,4 +2267,3 @@ void AutomationProvider::SaveAsAsync(int tab_handle) { if (tab_contents) tab_contents->OnSavePage(); } - diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index de371f8..24b381a 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -229,6 +229,9 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, void SetProxyConfig(const std::string& new_proxy_config); void IsFullscreen(int handle, bool* is_fullscreen); void GetFullscreenBubbleVisibility(int handle, bool* is_visible); +#if defined(OS_WIN) + void OnBrowserMoved(int handle); +#endif #if defined(OS_WIN) void ScheduleMouseEvent(views::View* view, diff --git a/chrome/browser/automation/automation_provider_win.cc b/chrome/browser/automation/automation_provider_win.cc index d5457e9..59d9867 100644 --- a/chrome/browser/automation/automation_provider_win.cc +++ b/chrome/browser/automation/automation_provider_win.cc @@ -506,3 +506,13 @@ void AutomationProvider::SetEnableExtensionAutomation( "SetEnableExtensionAutomation called with invalid tab handle."; } } + +void AutomationProvider::OnBrowserMoved(int tab_handle) { + ExternalTabContainer* external_tab = GetExternalTabForHandle(tab_handle); + if (external_tab) { + external_tab->WindowMoved(); + } else { + DLOG(WARNING) << + "AutomationProvider::OnBrowserMoved called with invalid tab handle."; + } +} diff --git a/chrome/browser/automation/chrome_frame_automation_provider.cc b/chrome/browser/automation/chrome_frame_automation_provider.cc index f9e82f7..ab87b92 100644 --- a/chrome/browser/automation/chrome_frame_automation_provider.cc +++ b/chrome/browser/automation/chrome_frame_automation_provider.cc @@ -35,6 +35,7 @@ bool ChromeFrameAutomationProvider::IsValidMessage(uint32 type) { case AutomationMsg_CreateExternalTab::ID: case AutomationMsg_ConnectExternalTab::ID: #if defined(OS_WIN) + case AutomationMsg_BrowserMove::ID: case AutomationMsg_ProcessUnhandledAccelerator::ID: case AutomationMsg_TabReposition::ID: case AutomationMsg_ForwardContextMenuCommandToChrome::ID: diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc index 9e098fd..837d006 100644 --- a/chrome/browser/external_tab_container.cc +++ b/chrome/browser/external_tab_container.cc @@ -256,7 +256,7 @@ void ExternalTabContainer::FocusThroughTabTraversal(bool reverse) { // static bool ExternalTabContainer::IsExternalTabContainer(HWND window) { - if (GetProp(window, kWindowObjectKey) != NULL) + if (::GetProp(window, kWindowObjectKey) != NULL) return true; return false; @@ -277,6 +277,17 @@ ExternalTabContainer* ExternalTabContainer::GetContainerForTab( return container; } +// static +ExternalTabContainer* + ExternalTabContainer::GetExternalContainerFromNativeWindow( + gfx::NativeView native_window) { + ExternalTabContainer* tab_container = NULL; + if (native_window) { + HANDLE handle = ::GetProp(native_window, kWindowObjectKey); + tab_container = reinterpret_cast<ExternalTabContainer*>(handle); + } + return tab_container; +} //////////////////////////////////////////////////////////////////////////////// // ExternalTabContainer, TabContentsDelegate implementation: diff --git a/chrome/browser/external_tab_container.h b/chrome/browser/external_tab_container.h index 0b25afb..154d258 100644 --- a/chrome/browser/external_tab_container.h +++ b/chrome/browser/external_tab_container.h @@ -13,6 +13,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/tab_contents/tab_contents_delegate.h" +#include "chrome/browser/views/frame/browser_bubble_host.h" #include "chrome/browser/views/infobars/infobar_container.h" #include "chrome/browser/views/unhandled_keyboard_event_handler.h" #include "chrome/common/navigation_types.h" @@ -39,7 +40,8 @@ class ExternalTabContainer : public TabContentsDelegate, public views::WidgetWin, public base::RefCounted<ExternalTabContainer>, public views::AcceleratorTarget, - public InfoBarContainer::Delegate { + public InfoBarContainer::Delegate, + public BrowserBubbleHost { public: typedef std::map<intptr_t, scoped_refptr<ExternalTabContainer> > PendingTabs; @@ -89,6 +91,12 @@ class ExternalTabContainer : public TabContentsDelegate, // ExternalTabContainer window static bool IsExternalTabContainer(HWND window); + // A helper function that returns a pointer to the ExternalTabContainer + // instance associated with a native view. Returns NULL if the window + // is not an ExternalTabContainer. + static ExternalTabContainer* GetExternalContainerFromNativeWindow( + gfx::NativeView native_window); + // A helper method that retrieves the ExternalTabContainer object that // hosts the given tab window. static ExternalTabContainer* GetContainerForTab(HWND tab_window); diff --git a/chrome/browser/views/browser_bubble.cc b/chrome/browser/views/browser_bubble.cc index 1b690db..b199680 100644 --- a/chrome/browser/views/browser_bubble.cc +++ b/chrome/browser/views/browser_bubble.cc @@ -6,20 +6,35 @@ #include "app/l10n_util.h" #include "chrome/browser/views/frame/browser_view.h" +#if defined(OS_WIN) +#include "chrome/browser/external_tab_container.h" +#endif #include "views/widget/root_view.h" #include "views/window/window.h" namespace { -BrowserView* GetBrowserViewFromFrame(views::Widget* frame) { - BrowserView* browser_view = NULL; +BrowserBubbleHost* GetBubbleHostFromFrame(views::Widget* frame) { + if (!frame) + return NULL; + + BrowserBubbleHost* bubble_host = NULL; views::Window* window = frame->GetWindow(); if (window) { - browser_view = BrowserView::GetBrowserViewForNativeWindow( + bubble_host = BrowserView::GetBrowserViewForNativeWindow( window->GetNativeWindow()); - DCHECK(browser_view); + DCHECK(bubble_host); + } +#if defined(OS_WIN) + // The frame may also be an ExternalTabContainer, which is also capable of + // hosting BrowserBubbles. + gfx::NativeView native_view = frame->GetNativeView(); + if (!bubble_host) { + bubble_host = + ExternalTabContainer::GetExternalContainerFromNativeWindow(native_view); } - return browser_view; +#endif + return bubble_host; } } // namespace @@ -31,7 +46,8 @@ BrowserBubble::BrowserBubble(views::View* view, views::Widget* frame, visible_(false), delegate_(NULL), attached_(false), - drop_shadow_enabled_(drop_shadow) { + drop_shadow_enabled_(drop_shadow), + bubble_host_(GetBubbleHostFromFrame(frame)) { gfx::Size size = view->GetPreferredSize(); bounds_.SetRect(origin.x(), origin.y(), size.width(), size.height()); InitPopup(); @@ -55,9 +71,8 @@ void BrowserBubble::DetachFromBrowser() { return; attached_ = false; - BrowserView* browser_view = GetBrowserViewFromFrame(frame_); - if (browser_view) - browser_view->DetachBrowserBubble(this); + if (bubble_host_) + bubble_host_->DetachBrowserBubble(this); } void BrowserBubble::AttachToBrowser() { @@ -65,9 +80,8 @@ void BrowserBubble::AttachToBrowser() { if (attached_) return; - BrowserView* browser_view = GetBrowserViewFromFrame(frame_); - if (browser_view) - browser_view->AttachBrowserBubble(this); + if (bubble_host_) + bubble_host_->AttachBrowserBubble(this); attached_ = true; } diff --git a/chrome/browser/views/browser_bubble.h b/chrome/browser/views/browser_bubble.h index 012c552..feb55f8 100644 --- a/chrome/browser/views/browser_bubble.h +++ b/chrome/browser/views/browser_bubble.h @@ -8,6 +8,8 @@ #include "views/view.h" #include "views/widget/widget.h" +class BrowserBubbleHost; + // A class for creating a floating window that is "attached" to a particular // Browser. If you don't install a delegate, the bubble will hide // automatically when the browser moves. The bubble is only shown manually. @@ -58,7 +60,7 @@ class BrowserBubble { Delegate* delegate() const { return delegate_; } void set_delegate(Delegate* del) { delegate_ = del; } - // Notifications from BrowserView. + // Notifications from BrowserBubbleHost. // With no delegate, both of these default to Hiding the bubble. virtual void BrowserWindowMoved(); virtual void BrowserWindowClosing(); @@ -120,6 +122,9 @@ class BrowserBubble { // Does the bubble have a drop-shadow. bool drop_shadow_enabled_; + // Non-owning pointer to the host of this bubble. + BrowserBubbleHost* bubble_host_; + DISALLOW_COPY_AND_ASSIGN(BrowserBubble); }; diff --git a/chrome/browser/views/frame/browser_bubble_host.cc b/chrome/browser/views/frame/browser_bubble_host.cc new file mode 100644 index 0000000..60809bf --- /dev/null +++ b/chrome/browser/views/frame/browser_bubble_host.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/frame/browser_bubble_host.h" + +#include "base/logging.h" +#include "chrome/browser/views/browser_bubble.h" + +void BrowserBubbleHost::WindowMoved() { + // Do safe iteration in case the bubble winds up closing as a result of this + // message. + for (BubbleSet::iterator i = browser_bubbles_.begin(); + i != browser_bubbles_.end();) { + BubbleSet::iterator bubble = i++; + (*bubble)->BrowserWindowMoved(); + } +} + +void BrowserBubbleHost::AttachBrowserBubble(BrowserBubble* bubble) { + DCHECK(browser_bubbles_.find(bubble) == browser_bubbles_.end()) << + "Attempt to register the same BrowserBubble multiple times."; + browser_bubbles_.insert(bubble); +} + +void BrowserBubbleHost::DetachBrowserBubble(BrowserBubble* bubble) { + BubbleSet::iterator it = browser_bubbles_.find(bubble); + DCHECK(it != browser_bubbles_.end()) << + "Attempt to detach an unrecognized BrowserBubble."; + if (it != browser_bubbles_.end()) + browser_bubbles_.erase(it); +} + +void BrowserBubbleHost::Close() { + // BrowserWindowClosing will usually cause the bubble to remove itself from + // the set, so we need to iterate in a way that's safe against deletion. + for (BubbleSet::iterator i = browser_bubbles_.begin(); + i != browser_bubbles_.end();) { + BubbleSet::iterator bubble = i++; + (*bubble)->BrowserWindowClosing(); + } +} + diff --git a/chrome/browser/views/frame/browser_bubble_host.h b/chrome/browser/views/frame/browser_bubble_host.h new file mode 100644 index 0000000..4763a50 --- /dev/null +++ b/chrome/browser/views/frame/browser_bubble_host.h @@ -0,0 +1,42 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_FRAME_BROWSER_BUBBLE_HOST_H_ +#define CHROME_BROWSER_VIEWS_FRAME_BROWSER_BUBBLE_HOST_H_ + +#include <set> + +#include "base/basictypes.h" + +class BrowserBubble; + +// A class providing a hosting environment for BrowserBubble instances. +// Allows for notification to attached BrowserBubbles of browser move, and +// close events. +class BrowserBubbleHost { + public: + BrowserBubbleHost() {} + + // Invoked when the window containing the attached browser-bubbles is moved. + // Calls BrowserBubble::BrowserWindowMoved on all attached bubbles. + void WindowMoved(); + + // To be called when the frame containing the BrowserBubbleHost is closing. + // Calls BrowserBubble::BrowserWindowClosing on all attached bubbles. + void Close(); + + // Registers/Unregisters |bubble| to receive notifications when the host moves + // or is closed. + void AttachBrowserBubble(BrowserBubble* bubble); + void DetachBrowserBubble(BrowserBubble* bubble); + + private: + // The set of bubbles associated with this host. + typedef std::set<BrowserBubble*> BubbleSet; + BubbleSet browser_bubbles_; + + DISALLOW_COPY_AND_ASSIGN(BrowserBubbleHost); +}; + +#endif // CHROME_BROWSER_VIEWS_FRAME_BROWSER_BUBBLE_HOST_H_ diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index b6a3e17..f3ccddf 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -486,13 +486,7 @@ void BrowserView::WindowMoved() { status_bubble_->Reposition(); - // Do safe iteration in case the bubble winds up closing as a result of this - // message. - for (BubbleSet::iterator i = browser_bubbles_.begin(); - i != browser_bubbles_.end();) { - BubbleSet::iterator bubble = i++; - (*bubble)->BrowserWindowMoved(); - } + BrowserBubbleHost::WindowMoved(); browser::HideBookmarkBubbleView(); @@ -653,16 +647,6 @@ void BrowserView::RegisterBrowserViewPrefs(PrefService* prefs) { kDefaultHungPluginDetectFrequency); } -void BrowserView::AttachBrowserBubble(BrowserBubble* bubble) { - browser_bubbles_.insert(bubble); -} - -void BrowserView::DetachBrowserBubble(BrowserBubble* bubble) { - BubbleSet::iterator it = browser_bubbles_.find(bubble); - if (it != browser_bubbles_.end()) - browser_bubbles_.erase(it); -} - bool BrowserView::IsPositionInWindowCaption(const gfx::Point& point) { return GetBrowserViewLayout()->IsPositionInWindowCaption(point); } @@ -712,13 +696,7 @@ void BrowserView::SetBounds(const gfx::Rect& bounds) { } void BrowserView::Close() { - // BrowserWindowClosing will usually cause the bubble to remove itself from - // the set, so we need to iterate in a way that's safe against deletion. - for (BubbleSet::iterator i = browser_bubbles_.begin(); - i != browser_bubbles_.end();) { - BubbleSet::iterator bubble = i++; - (*bubble)->BrowserWindowClosing(); - } + BrowserBubbleHost::Close(); frame_->GetWindow()->Close(); } diff --git a/chrome/browser/views/frame/browser_view.h b/chrome/browser/views/frame/browser_view.h index 02fa1e0..7732621 100644 --- a/chrome/browser/views/frame/browser_view.h +++ b/chrome/browser/views/frame/browser_view.h @@ -17,6 +17,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/tabs/tab_strip_model.h" +#include "chrome/browser/views/frame/browser_bubble_host.h" #include "chrome/browser/views/frame/browser_frame.h" #include "chrome/browser/views/infobars/infobar_container.h" #include "chrome/browser/views/tabs/tab_strip.h" @@ -67,7 +68,8 @@ class SingleSplitView; // A ClientView subclass that provides the contents of a browser window, // including the TabStrip, toolbars, download shelves, the content area etc. // -class BrowserView : public BrowserWindow, +class BrowserView : public BrowserBubbleHost, + public BrowserWindow, public BrowserWindowTesting, public NotificationObserver, public TabStripModelObserver, @@ -216,10 +218,6 @@ class BrowserView : public BrowserWindow, // Register preferences specific to this view. static void RegisterBrowserViewPrefs(PrefService* prefs); - // Attach/Detach a BrowserBubble to the browser. - void AttachBrowserBubble(BrowserBubble *bubble); - void DetachBrowserBubble(BrowserBubble *bubble); - // Returns true if the specified point(BrowserView coordinates) is in // in the window caption area of the browser window. bool IsPositionInWindowCaption(const gfx::Point& point); @@ -561,9 +559,6 @@ class BrowserView : public BrowserWindow, // A bottom bar for showing extensions. ExtensionShelf* extension_shelf_; - typedef std::set<BrowserBubble*> BubbleSet; - BubbleSet browser_bubbles_; - // The accessible name of this view. std::wstring accessible_name_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index c548fe5..aafc27e 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1929,6 +1929,8 @@ 'browser/views/first_run_view_base.h', 'browser/views/frame/app_panel_browser_frame_view.cc', 'browser/views/frame/app_panel_browser_frame_view.h', + 'browser/views/frame/browser_bubble_host.cc', + 'browser/views/frame/browser_bubble_host.h', 'browser/views/frame/browser_extender.cc', 'browser/views/frame/browser_extender.h', 'browser/views/frame/browser_frame.h', @@ -2521,6 +2523,8 @@ ['include', '^browser/views/theme_install_bubble_view.h'], ['include', '^browser/views/toolbar_star_toggle.h'], ['include', '^browser/views/toolbar_star_toggle.cc'], + ['include', '^browser/views/frame/browser_bubble_host.cc'], + ['include', '^browser/views/frame/browser_bubble_host.h'], ['include', '^browser/views/frame/browser_view_layout.cc'], ['include', '^browser/views/frame/browser_view_layout.h'], ['include', '^browser/views/frame/browser_extender.cc'], diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h index a3f4945..eb74875 100644 --- a/chrome/test/automation/automation_messages_internal.h +++ b/chrome/test/automation/automation_messages_internal.h @@ -1192,4 +1192,11 @@ IPC_BEGIN_MESSAGES(Automation) IPC_MESSAGE_ROUTED1(AutomationMsg_SaveAsAsync, int /* tab handle */) +#if defined(OS_WIN) + // An incoming message from an automation host to Chrome. Signals that + // the browser containing |tab_handle| has moved. + IPC_MESSAGE_ROUTED1(AutomationMsg_BrowserMove, + int /* tab handle */) +#endif + IPC_END_MESSAGES(Automation) diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc index ccef84a..dbf4875 100644 --- a/chrome/test/automation/tab_proxy.cc +++ b/chrome/test/automation/tab_proxy.cc @@ -708,6 +708,10 @@ void TabProxy::SendContextMenuCommand(int selected_command) { sender_->Send(new AutomationMsg_ForwardContextMenuCommandToChrome( 0, handle_, selected_command)); } + +void TabProxy::OnHostMoved() { + sender_->Send(new AutomationMsg_BrowserMove(0, handle_)); +} #endif // defined(OS_WIN) void TabProxy::SelectAll() { diff --git a/chrome/test/automation/tab_proxy.h b/chrome/test/automation/tab_proxy.h index d8055fa..326f0dc 100644 --- a/chrome/test/automation/tab_proxy.h +++ b/chrome/test/automation/tab_proxy.h @@ -360,6 +360,9 @@ class TabProxy : public AutomationResourceProxy { // Sends the selected context menu command to the chrome instance void SendContextMenuCommand(int selected_command); + + // To be called when the window hosting the tab has moved. + void OnHostMoved(); #endif // defined(OS_WIN) // Selects all contents on the page. diff --git a/chrome_frame/chrome_frame_activex.cc b/chrome_frame/chrome_frame_activex.cc index 295ceaa..15ae065 100644 --- a/chrome_frame/chrome_frame_activex.cc +++ b/chrome_frame/chrome_frame_activex.cc @@ -7,6 +7,7 @@ #include <wininet.h> #include <algorithm> +#include <map> #include "base/basictypes.h" #include "base/command_line.h" @@ -15,6 +16,7 @@ #include "base/path_service.h" #include "base/process_util.h" #include "base/scoped_bstr_win.h" +#include "base/singleton.h" #include "base/string_util.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" @@ -22,7 +24,94 @@ #include "googleurl/src/gurl.h" #include "chrome_frame/utils.h" -ChromeFrameActivex::ChromeFrameActivex() { +namespace { + +// Class used to maintain a mapping from top-level windows to ChromeFrameActivex +// instances. +class TopLevelWindowMapping { + public: + typedef std::vector<HWND> WindowList; + + static TopLevelWindowMapping* instance() { + return Singleton<TopLevelWindowMapping>::get(); + } + + // Add |cf_window| to the set of windows registered under |top_window|. + void AddMapping(HWND top_window, HWND cf_window) { + top_window_map_lock_.Lock(); + top_window_map_[top_window].push_back(cf_window); + top_window_map_lock_.Unlock(); + } + + // Return the set of Chrome-Frame instances under |window|. + WindowList GetInstances(HWND window) { + top_window_map_lock_.Lock(); + WindowList list = top_window_map_[window]; + top_window_map_lock_.Unlock(); + return list; + } + + private: + // Constructor is private as this class it to be used as a singleton. + // See static method instance(). + TopLevelWindowMapping() {} + + friend struct DefaultSingletonTraits<TopLevelWindowMapping>; + + typedef std::map<HWND, WindowList> TopWindowMap; + TopWindowMap top_window_map_; + + CComAutoCriticalSection top_window_map_lock_; + + DISALLOW_COPY_AND_ASSIGN(TopLevelWindowMapping); +}; + +// Message pump hook function that monitors for WM_MOVE and WM_MOVING +// messages on a top-level window, and passes notification to the appropriate +// Chrome-Frame instances. +LRESULT CALLBACK TopWindowProc(int code, WPARAM wparam, LPARAM lparam) { + CWPSTRUCT *info = reinterpret_cast<CWPSTRUCT*>(lparam); + const UINT &message = info->message; + const HWND &message_hwnd = info->hwnd; + + switch (message) { + case WM_MOVE: + case WM_MOVING: { + TopLevelWindowMapping::WindowList cf_instances = + TopLevelWindowMapping::instance()->GetInstances(message_hwnd); + TopLevelWindowMapping::WindowList::iterator + iter(cf_instances.begin()), end(cf_instances.end()); + for (;iter != end; ++iter) { + PostMessage(*iter, WM_HOST_MOVED_NOTIFICATION, NULL, NULL); + } + break; + } + default: + break; + } + + return CallNextHookEx(0, code, wparam, lparam); +} + +HHOOK InstallLocalWindowHook(HWND window) { + if (!window) + return NULL; + + DWORD proc_thread = ::GetWindowThreadProcessId(window, NULL); + if (!proc_thread) + return NULL; + + // Note that this hook is installed as a LOCAL hook. + return ::SetWindowsHookEx(WH_CALLWNDPROC, + TopWindowProc, + NULL, + proc_thread); +} + +} // unnamed namespace + +ChromeFrameActivex::ChromeFrameActivex() + : chrome_wndproc_hook_(NULL) { } HRESULT ChromeFrameActivex::FinalConstruct() { @@ -43,6 +132,11 @@ ChromeFrameActivex::~ChromeFrameActivex() { DCHECK(onreadystatechanged_.size() == 0); DCHECK(onextensionready_.size() == 0); + if (chrome_wndproc_hook_) { + BOOL unhook_success = ::UnhookWindowsHookEx(chrome_wndproc_hook_); + DCHECK(unhook_success); + } + // ChromeFramePlugin::Uninitialize() Base::Uninitialize(); } @@ -50,6 +144,17 @@ ChromeFrameActivex::~ChromeFrameActivex() { LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) { Base::OnCreate(message, wparam, lparam, handled); + // Install the notification hook on the top-level window, so that we can + // be notified on move events. Note that the return value is not checked. + // This hook is installed here, as opposed to during IOleObject_SetClientSite + // because m_hWnd has not yet been assigned during the SetSite call. + InstallTopLevelHook(m_spClientSite); + return 0; +} + +LRESULT ChromeFrameActivex::OnHostMoved(UINT message, WPARAM wparam, + LPARAM lparam, BOOL& handled) { + Base::OnHostMoved(); return 0; } @@ -449,3 +554,24 @@ void ChromeFrameActivex::FireEvent(const EventHandlers& handlers, << StringPrintf(L"Failed to invoke script: 0x%08X", hr); } } + +HRESULT ChromeFrameActivex::InstallTopLevelHook(IOleClientSite* client_site) { + // Get the parent window of the site, and install our hook on the topmost + // window of the parent. + ScopedComPtr<IOleWindow> ole_window; + HRESULT hr = ole_window.QueryFrom(client_site); + if (FAILED(hr)) + return hr; + + HWND parent_wnd; + hr = ole_window->GetWindow(&parent_wnd); + if (FAILED(hr)) + return hr; + + HWND top_window = ::GetAncestor(parent_wnd, GA_ROOT); + chrome_wndproc_hook_ = InstallLocalWindowHook(top_window); + if (chrome_wndproc_hook_) + TopLevelWindowMapping::instance()->AddMapping(top_window, m_hWnd); + + return chrome_wndproc_hook_ ? S_OK : E_FAIL; +} diff --git a/chrome_frame/chrome_frame_activex.h b/chrome_frame/chrome_frame_activex.h index 31c85b1..1d4f1e9 100644 --- a/chrome_frame/chrome_frame_activex.h +++ b/chrome_frame/chrome_frame_activex.h @@ -22,6 +22,8 @@ // Include without path to make GYP build see it. #include "chrome_tab.h" // NOLINT +#define WM_HOST_MOVED_NOTIFICATION (WM_APP + 1) + // ChromeFrameActivex: Implementation of the ActiveX control that is // responsible for hosting a chrome frame, i.e. an iframe like widget which // hosts the the chrome window. This object delegates to Chrome.exe @@ -48,6 +50,7 @@ END_COM_MAP() BEGIN_MSG_MAP(ChromeFrameActivex) MESSAGE_HANDLER(WM_CREATE, OnCreate) + MESSAGE_HANDLER(WM_HOST_MOVED_NOTIFICATION, OnHostMoved) CHAIN_MSG_MAP(Base) END_MSG_MAP() @@ -74,7 +77,7 @@ END_MSG_MAP() // Used to setup the document_url_ member needed for completing navigation. // Create external tab (possibly in incognito mode). - HRESULT IOleObject_SetClientSite(IOleClientSite *pClientSite); + HRESULT IOleObject_SetClientSite(IOleClientSite* client_site); // Overridden to perform security checks. STDMETHOD(put_src)(BSTR src); @@ -95,6 +98,8 @@ END_MSG_MAP() private: LRESULT OnCreate(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled); // NO_LINT + LRESULT OnHostMoved(UINT message, WPARAM wparam, LPARAM lparam, + BOOL& handled); // NO_LINT HRESULT GetContainingDocument(IHTMLDocument2** doc); HRESULT GetDocumentWindow(IHTMLWindow2** window); @@ -123,6 +128,11 @@ END_MSG_MAP() void FireEvent(const EventHandlers& handlers, IDispatch* event, BSTR target); + // Installs a hook on the top-level window hosting the control. + HRESULT InstallTopLevelHook(IOleClientSite* client_site); + + // A hook attached to the top-level window containing the ActiveX control. + HHOOK chrome_wndproc_hook_; }; #endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_H_ diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc index f505ffe..5775d3b 100644 --- a/chrome_frame/chrome_frame_automation.cc +++ b/chrome_frame/chrome_frame_automation.cc @@ -705,6 +705,10 @@ void ChromeFrameAutomationClient::InstallExtensionComplete( } } +void ChromeFrameAutomationClient::OnChromeFrameHostMoved() { + tab_->OnHostMoved(); +} + void ChromeFrameAutomationClient::LoadExpandedExtension( const FilePath& path, void* user_data) { diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h index 8b2f801..f9e37c4 100644 --- a/chrome_frame/chrome_frame_automation.h +++ b/chrome_frame/chrome_frame_automation.h @@ -191,6 +191,8 @@ class ChromeFrameAutomationClient void* user_data, AutomationMsg_ExtensionResponseValues res); + virtual void OnChromeFrameHostMoved(); + TabProxy* tab() const { return tab_.get(); } BEGIN_MSG_MAP(ChromeFrameAutomationClient) diff --git a/chrome_frame/chrome_frame_delegate.h b/chrome_frame/chrome_frame_delegate.h index 49ae1c1..11eaa30 100644 --- a/chrome_frame/chrome_frame_delegate.h +++ b/chrome_frame/chrome_frame_delegate.h @@ -37,6 +37,10 @@ class ChromeFrameDelegate { // messages. virtual bool IsValid() const = 0; + // To be called when the top-most window of an application hosting + // ChromeFrame is moved. + virtual void OnHostMoved() = 0; + protected: ~ChromeFrameDelegate() {} }; @@ -71,6 +75,8 @@ class ChromeFrameDelegateImpl : public ChromeFrameDelegate { return true; } + virtual void OnHostMoved() {} + protected: // Protected methods to be overriden. virtual void OnNavigationStateChanged(int tab_handle, int flags, diff --git a/chrome_frame/chrome_frame_plugin.h b/chrome_frame/chrome_frame_plugin.h index 293cb99..be85e26 100644 --- a/chrome_frame/chrome_frame_plugin.h +++ b/chrome_frame/chrome_frame_plugin.h @@ -86,6 +86,10 @@ END_MSG_MAP() return automation_client_.get() != NULL; } + virtual void OnHostMoved() { + automation_client_->OnChromeFrameHostMoved(); + } + protected: virtual void OnNavigationFailed(int tab_handle, int error_code, const GURL& gurl) { |