Chromium Code Reviews| Index: chrome_frame/infobar_manager.cc |
| =================================================================== |
| --- chrome_frame/infobar_manager.cc (revision 0) |
| +++ chrome_frame/infobar_manager.cc (revision 0) |
| @@ -0,0 +1,268 @@ |
| +// 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. |
| +// |
| +// Implementation of the manager for infobar windows. |
| + |
| +#include "chrome_frame/infobar_manager.h" |
| + |
| +#include <atlbase.h> |
| +#include <atlapp.h> // Must be included AFTER base. |
| +#include <atlcrack.h> |
| +#include <atlmisc.h> |
| +#include <atlwin.h> |
| + |
| +#include "base/logging.h" |
| +#include "base/task_queue.h" |
| +//#include "ceee/common/windows_constants.h" |
| +#include "chrome_frame/utils.h" |
| + |
| +namespace { |
| + |
| +const wchar_t kIeTabContentParentWindowClass[] = L"Shell DocObject View"; |
| + |
| +} // namespace |
| + |
| +DISABLE_RUNNABLE_METHOD_REFCOUNT(InfobarManager); |
| +DISABLE_RUNNABLE_METHOD_REFCOUNT(InfobarManager::DisplacedWindowManager); |
| + |
| + |
| +InfobarManager::InfobarHostImpl::InfobarHostImpl(InfobarManager *manager) |
| + : manager_(manager) { |
| +} |
| + |
| +HWND InfobarManager::InfobarHostImpl::GetContainerWindow() { |
| + return manager_->container_window_; |
| +} |
| + |
| +void InfobarManager::InfobarHostImpl::UpdateLayout() { |
| + manager_->UpdateLayout(); |
| +} |
| + |
| +// DisplacedWindowManager subclasses IE content window's container window, |
| +// handles WM_NCCALCSIZE to resize its client area. It also handles WM_SIZE and |
| +// WM_MOVE messages to make infobars consistent with IE content window's size |
| +// and position. |
| +// |
| +// Finally, allows delayed tasks to be scheduled on the window's event loop. |
| +class InfobarManager::DisplacedWindowManager |
| + : public CWindowImpl<DisplacedWindowManager> { |
| + public: |
| + DisplacedWindowManager(InfobarManager* manager) |
| + : infobar_manager_(manager) { |
| + } |
| + |
| + // Returns true if the window is successfully subclassed, in which case this |
| + // instance will take responsibility for its own destruction when the window |
| + // is destroyed. If this method returns false, the caller should delete the |
| + // instance immediately. |
| + bool Initialize(HWND displaced_hwnd) { |
| + PinModule(); |
| + if (!SubclassWindow(displaced_hwnd)) { |
| + LOG(DFATAL) << "Failed to subclass IE Renderer HWND for infobar " |
| + << "installation."; |
| + return false; |
| + } |
| + return true; |
| + } |
| + |
| + virtual ~DisplacedWindowManager() { |
| + if (IsWindow()) |
| + UnsubclassWindow(); |
| + } |
| + |
| + // Triggers a deferred re-evaluation of the dimensions of the displaced |
| + // window. InfobarManager::AdjustDisplacedWindowDimensions will be called |
| + // with the natural dimensions of the displaced window. |
| + virtual void UpdateLayout() { |
| + PushTask( |
| + NewRunnableMethod(this, &DisplacedWindowManager::DoUpdateLayout)); |
| + } |
| + |
| + // Schedules a deferred task on the window message loop of this instance's |
| + // managed window. The task may not occur if the window is destroyed first. |
| + virtual void PushTask(Task* task) { |
| + task_queue_.Push(task); |
| + if (IsWindow()) |
| + PostMessage(TM_RUN_TASK_QUEUE, 0, 0); |
| + } |
| + |
| + BEGIN_MSG_MAP_EX(DisplacedWindowManager) |
| + MSG_WM_NCCALCSIZE(OnNcCalcSize) |
| + MSG_WM_DESTROY(OnDestroy) |
| + MESSAGE_HANDLER(TM_RUN_TASK_QUEUE, OnRunTaskQueue) |
| + END_MSG_MAP() |
| + |
| + private: |
| + enum DisplacedWindowUserMessages { |
| + TM_RUN_TASK_QUEUE = WM_USER + 600, |
| + }; |
| + |
| + LRESULT OnRunTaskQueue(UINT message, |
| + WPARAM wparam, |
| + LPARAM lparam, |
| + BOOL& handled) { |
| + task_queue_.Run(); |
| + handled = TRUE; |
| + return 0; |
| + } |
| + |
| + void DoUpdateLayout() { |
| + // Call SetWindowPos with SWP_FRAMECHANGED for IE window, then IE |
| + // window would receive WM_NCCALCSIZE to recalculate its client size. |
| + if (IsWindow()) |
| + ::SetWindowPos(m_hWnd, |
| + NULL, 0, 0, 0, 0, |
| + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | |
| + SWP_FRAMECHANGED); |
| + } |
| + |
| + // Handles WM_NCCALCSIZE message. |
| + LRESULT OnNcCalcSize(BOOL calc_valid_rects, LPARAM lparam) { |
| + // Adjust client area for infobar. |
| + LRESULT ret = DefWindowProc(WM_NCCALCSIZE, |
| + static_cast<WPARAM>(calc_valid_rects), lparam); |
| + // Whether calc_valid_rects is true or false, we could treat beginning of |
| + // lparam as a RECT object. |
| + RECT* rect = reinterpret_cast<RECT*>(lparam); |
| + if (infobar_manager_ != NULL) |
| + infobar_manager_->AdjustDisplacedWindowDimensions(rect); |
| + |
| + // If infobars reserve all the space and rect becomes empty, the container |
| + // window won't receive subsequent WM_SIZE and WM_MOVE messages. |
| + // In this case, we have to explicitly notify infobars to update their |
| + // position. |
| + //if (rect->right - rect->left <= 0 || rect->bottom - rect->top <= 0) |
| + // PushTask( |
| + // NewRunnableMethod(infobar_manager_, |
| + // &InfobarManager::OnDisplacedWindowPositionChange)); |
| + return ret; |
| + } |
| + |
| + // The displaced window has been destroyed. Inform the InfobarManager, who |
| + // will orphan this instance. We will delete ourselves in OnFinalMessage. |
| + void OnDestroy() { |
| + infobar_manager_->OnDisplacedWindowDestroyed(); |
| + } |
| + |
| + void OnFinalMessage(HWND) { |
| + delete this; |
| + } |
| + |
| + InfobarManager* infobar_manager_; |
| + TaskQueue task_queue_; |
| + DISALLOW_COPY_AND_ASSIGN(DisplacedWindowManager); |
| +}; |
| + |
| +InfobarManager::InfobarManager(HWND tab_window) |
| + : container_window_(tab_window), |
| + displaced_window_manager_(NULL), |
| + infobar_host_impl_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { |
| + for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { |
|
amit
2010/11/12 00:04:49
Feels like an overkill for our rudimentary infobar
erikwright (departed)
2010/11/24 06:24:56
The TOP vs BOTTOM and sliding is unnecessary, but
|
| + infobars_[index].reset( |
| + new InfobarWindow(static_cast<InfobarType>(index), |
| + &infobar_host_impl_)); |
| + } |
| +} |
| + |
| +HRESULT InfobarManager::Show(InfobarContent* content, |
| + InfobarType type, |
| + int max_height) { |
| + if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE || |
|
grt (UTC plus 2)
2010/11/10 17:59:29
This looks like programmer error. Change to DCHEC
erikwright (departed)
2010/11/24 06:24:56
Yes. A relic of the original code. Ideally, I'd li
|
| + infobars_[type] == NULL) { |
|
grt (UTC plus 2)
2010/11/10 17:59:29
How about this one, programmer error or something
erikwright (departed)
2010/11/24 06:24:56
Yes. I'm updating it to only return success or fai
|
| + return E_INVALIDARG; |
| + } |
| + |
| + HRESULT hr = infobars_[type]->Show(content, max_height); |
| + return hr; |
| +} |
| + |
| +bool InfobarManager::UpdateLayout() { |
| + if (FindDisplacedWindow()) { |
| + displaced_window_manager_->UpdateLayout(); |
| + return true; |
| + } else { |
| + return false; |
| + } |
| +} |
| + |
| +HRESULT InfobarManager::Hide(InfobarType type) { |
| + if (type < FIRST_INFOBAR_TYPE || type >= END_OF_INFOBAR_TYPE || |
| + infobars_[type] == NULL) { |
| + return E_INVALIDARG; |
| + } |
| + |
| + infobars_[type]->Hide(); |
| + return S_OK; |
| +} |
| + |
| +void InfobarManager::HideAll() { |
| + for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) |
| + Hide(static_cast<InfobarType>(index)); |
| +} |
| + |
| +// Callback function for EnumChildWindows. lParam should be the pointer to |
| +// HWND variable where the handle of the window which class is |
| +// kIeTabContentParentWindowClass will be written. |
| +static BOOL CALLBACK FindDisplacedWindowProc(HWND hwnd, LPARAM lparam) { |
| + HWND* window_handle = reinterpret_cast<HWND*>(lparam); |
| + if (NULL == window_handle) { |
|
grt (UTC plus 2)
2010/11/10 17:59:29
I prefer this style of comparison. For consistenc
erikwright (departed)
2010/11/24 06:24:56
Agreed. Not the least because scoped_ptr does not
|
| + // It makes no sense to continue enumeration. |
| + return FALSE; |
| + } |
| + |
| + // Variable to hold the class name. The size does not matter as long as it |
| + // is at least can hold kIeTabContentParentWindowClass. |
| + wchar_t class_name[100]; |
| + if (::GetClassName(hwnd, class_name, arraysize(class_name)) && |
| + lstrcmpi(kIeTabContentParentWindowClass, class_name) == 0) { |
| + // We found the window. Return its handle and stop enumeration. |
| + *window_handle = hwnd; |
| + return FALSE; |
| + } |
| + return TRUE; |
| +} |
| + |
| +bool InfobarManager::FindDisplacedWindow() { |
| + if (displaced_window_manager_ == NULL) { |
| + if (::IsWindow(container_window_)) { |
| + // Find the window which is the container for the HTML view (parent of |
| + // the content). |
| + HWND displaced_window = NULL; |
| + ::EnumChildWindows(container_window_, FindDisplacedWindowProc, |
| + reinterpret_cast<LPARAM>(&displaced_window)); |
| + |
| + if (displaced_window == NULL) { |
| + LOG(DFATAL) << "Failed to locate IE renderer HWND to displace for " |
| + << "Infobar installation."; |
| + } else { |
| + scoped_ptr<DisplacedWindowManager> displaced_window_manager( |
| + new DisplacedWindowManager(this)); |
| + if (displaced_window_manager->Initialize(displaced_window)) { |
| + displaced_window_manager_ = displaced_window_manager.release(); |
| + } |
| + } |
| + } |
| + } |
| + |
| + return displaced_window_manager_ != NULL; |
| +} |
| + |
| +void InfobarManager::AdjustDisplacedWindowDimensions(RECT* rect) { |
| + if (rect == NULL) |
| + return; |
| + |
| + for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { |
| + if (infobars_[index] != NULL) |
| + infobars_[index]->ReserveSpace(rect); |
| + } |
| +} |
| + |
| +void InfobarManager::OnDisplacedWindowDestroyed() { |
| + for (int index = 0; index < END_OF_INFOBAR_TYPE; ++index) { |
| + if (infobars_[index] != NULL) |
| + infobars_[index]->Hide(); |
| + } |
| + // Will be deleted in its OnFinalMessage |
| + displaced_window_manager_ = NULL; |
| +} |